2015-05-26 4 views
13

मैं एक Django ऐप लिख रहा हूं, और मुझे डेटाबेस में फ़ील्ड को अपडेट करने के लिए एक फ़ंक्शन की आवश्यकता है। क्या दूसरे तरीकों के बजाय इन तरीकों में से कोई एक करने का कोई कारण है?Django: डेटाबेस को अद्यतन करने के लिए() बनाम अपडेट() को सहेजें?

def save_db_field(name,field,value): 
    obj = MyModel.objects.get(name=name) 
    obj.field = value 
    obj.save() 

def update_db_field(name,field,value): 
    MyModel.objects.get(name=name).update(field=value) 

ऐसा लगता है कि दूसरा बेहतर है क्योंकि यह दो की बजाय एक डीबी कॉल में करता है। क्या कोई कारण है कि लाने का कोई कारण है, तो अद्यतन करना बेहतर है?

+1

के संभावित डुप्लिकेट ([QuerySet.update() का उपयोग Django में ModelInstance.save() बनाम] http://stackoverflow.com/questions/4519336/using-queryset-update-versus-modelinstance-save- in-django) – sobolevn

+1

@sobolevn कि प्रश्न और उत्तर काफी पुराने हैं क्योंकि django संस्करण 1.0 या 1.1 में था या ऐसा कुछ था। उन कथनों को बहिष्कृत कर दिया गया है और समय के दौरान बहुत सारे बदलाव हुए हैं, इसलिए अब और समर्थित नहीं है। – FallenAngel

+0

@FallenAngel, हाँ, पहले तारीख को देखा है। लेकिन जब मैंने इसे समझ लिया, तो मैंने जवाब दिया। – sobolevn

उत्तर

14

कई महत्वपूर्ण अंतर हैं।

update किसी क्वेरीसेट पर उपयोग किया जाता है, इसलिए एक साथ कई ऑब्जेक्ट्स अपडेट करना संभव है।

रूप @FallenAngel ने बताया, वहाँ कैसे कस्टम save() विधि से चलाता में मतभेद हैं, लेकिन यह भी मन signals और ModelManagers में रखने के लिए महत्वपूर्ण है। मैंने कुछ मूल्यवान भिन्नताओं को दिखाने के लिए एक छोटा परीक्षण ऐप बनाया है। मैं पाइथन 2.7.5, Django == 1.7.7 और SQLite का उपयोग कर रहा हूं, ध्यान दें कि अंतिम SQLs Django और विभिन्न डेटाबेस इंजन के विभिन्न संस्करणों पर भिन्न हो सकता है।

ठीक है, यहां उदाहरण कोड है।

models.py:

from __future__ import print_function 
from django.db import models 
from django.db.models import signals 
from django.db.models.signals import pre_save, post_save 
from django.dispatch import receiver 

__author__ = 'sobolevn' 

class CustomManager(models.Manager): 
    def get_queryset(self): 
     super_query = super(models.Manager, self).get_queryset() 
     print('Manager is called', super_query) 
     return super_query 


class ExtraObject(models.Model): 
    name = models.CharField(max_length=30) 

    def __unicode__(self): 
     return self.name 


class TestModel(models.Model): 

    name = models.CharField(max_length=30) 
    key = models.ForeignKey('ExtraObject') 
    many = models.ManyToManyField('ExtraObject', related_name='extras') 

    objects = CustomManager() 

    def save(self, *args, **kwargs): 
     print('save() is called.') 
     super(TestModel, self).save(*args, **kwargs) 

    def __unicode__(self): 
     # Never do such things (access by foreing key) in real life, 
     # because it hits the database. 
     return u'{} {} {}'.format(self.name, self.key.name, self.many.count()) 


@receiver(pre_save, sender=TestModel) 
@receiver(post_save, sender=TestModel) 
def reicever(*args, **kwargs): 
    print('signal dispatched') 

views.py:

def index(request): 
    if request and request.method == 'GET': 

     from models import ExtraObject, TestModel 

     # Create exmple data if table is empty: 
     if TestModel.objects.count() == 0: 
      for i in range(15): 
       extra = ExtraObject.objects.create(name=str(i)) 
       test = TestModel.objects.create(key=extra, name='test_%d' % i) 
       test.many.add(test) 
       print test 

     to_edit = TestModel.objects.get(id=1) 
     to_edit.name = 'edited_test' 
     to_edit.key = ExtraObject.objects.create(name='new_for') 
     to_edit.save() 

     new_key = ExtraObject.objects.create(name='new_for_update') 
     to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key) 
     # return any kind of HttpResponse 

कि इन एसक्यूएल प्रश्नों में resuled:

# to_edit = TestModel.objects.get(id=1): 
QUERY = u'SELECT "main_testmodel"."id", "main_testmodel"."name", "main_testmodel"."key_id" 
FROM "main_testmodel" 
WHERE "main_testmodel"."id" = %s LIMIT 21' 
- PARAMS = (u'1',) 

# to_edit.save(): 
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s 
WHERE "main_testmodel"."id" = %s' 
- PARAMS = (u"'edited_test'", u'2', u'1') 

# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key): 
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s 
WHERE "main_testmodel"."id" = %s' 
- PARAMS = (u"'updated_name'", u'3', u'2') 

हम update() और save() के लिए दो लोगों के लिए सिर्फ एक ही प्रश्न हैं।

अगला, save() विधि ओवरराइड करने के बारे में बात करते हैं। इसे स्पष्ट रूप से save() विधि के लिए केवल एक बार कहा जाता है। उल्लेखनीय है कि .objects.create() भी save() विधि को कॉल करता है।

लेकिन update() मॉडल पर save() पर कॉल नहीं करता है। और यदि विधि update() के लिए विधि कहा जाता है, तो संकेतों को या तो ट्रिगर नहीं किया जाता है। आउटपुट:

Starting development server at http://127.0.0.1:8000/ 
Quit the server with CONTROL-C. 

# TestModel.objects.get(id=1): 
Manager is called [<TestModel: edited_test new_for 0>] 
Manager is called [<TestModel: edited_test new_for 0>] 
save() is called. 
signal dispatched 
signal dispatched 

# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key): 
Manager is called [<TestModel: edited_test new_for 0>] 

आप save() देख सकते हैं चलाता है Manager के get_queryset() दो बार। जब update() केवल एक बार।

संकल्प। यदि आपको save() के बिना अपने मूल्यों को "चुपचाप" अपडेट करने की आवश्यकता है, तो update का उपयोग करें। उपयोग: last_seen उपयोगकर्ता का क्षेत्र। जब आपको अपने मॉडल को अपडेट करने की आवश्यकता होती है तो save() का उपयोग करें।

2

सेव() विधि का उपयोग नए रिकॉर्ड को सम्मिलित करने और मौजूदा रिकॉर्ड को अपडेट करने के लिए किया जा सकता है और आमतौर पर डेटाबेस में एकल रिकॉर्ड (mysql में पंक्ति) को सहेजने के लिए उपयोग किया जाता है।

अद्यतन() का उपयोग रिकॉर्ड डालने के लिए नहीं किया जाता है और डेटाबेस में एकाधिक रिकॉर्ड (mysql में पंक्तियों) को अद्यतन करने के लिए उपयोग किया जा सकता है।

2

अद्यतन केवल क्वेरीसेट अपडेट करने पर काम करता है। आप एक ही समय में एक से अधिक फ़ील्ड अद्यतन करना चाहते हैं, तो एक वस्तु उदाहरण आप की तरह कुछ कर सकते हैं के लिए एक dict से कहते हैं: मन में

obj.__dict__.update(your_dict) 
obj.save() 

भालू है कि अपने शब्दकोश सही मानचित्रण शामिल करना होगा जहां कुंजी अपने फील्ड नाम और मूल्यों को मानने की आवश्यकता है जिन्हें आप सम्मिलित करना चाहते हैं।

11

दोनों समान दिखता है, लेकिन कुछ महत्वपूर्ण बिंदु हैं:

  1. save() किसी भी अधिरोहित Model.save() विधि ट्रिगर होंगे, लेकिन update() इस ट्रिगर नहीं करेगा और डेटाबेस स्तर पर सीधा अद्यतन करते हैं। इसलिए यदि आपके पास ओवरराइड सेव विधियों के साथ कुछ मॉडल हैं, तो आपको या तो अद्यतन का उपयोग करने से बचने या उस ओवरराइड save() विधियों पर जो कुछ भी कर रहे हैं, उसे करने का एक और तरीका ढूंढना चाहिए।

  2. obj.save() यदि आप सावधान नहीं हैं तो कुछ दुष्प्रभाव हो सकते हैं। आप ऑब्जेक्ट को get(...) से पुनर्प्राप्त करते हैं और सभी मॉडल फ़ील्ड मान आपके ओबीजे में पास किए जाते हैं। जब आप obj.save() पर कॉल करते हैं, तो django वर्तमान ऑब्जेक्ट स्थिति को रिकॉर्ड करने के लिए सहेज लेगा। तो अगर कुछ बदलाव किसी अन्य प्रक्रिया द्वारा get() और save() के बीच होता है, तो वे परिवर्तन खो जाएंगे। ऐसी समस्याओं से बचने के लिए save(update_fields=[.....]) का उपयोग करें।

  3. Django संस्करण 1.5 से पहले, Django को INSERT/UPDATE से पहले निष्पादित कर रहा था, इसलिए इसमें 2 क्वेरी निष्पादन की लागत है। संस्करण 1.5 के साथ, उस विधि को बहिष्कृत किया गया है।

In here, वहाँ एक अच्छा गाइड या save() और update() तरीकों है और वे कैसे क्रियान्वित कर रहे हैं।

2

अपडेट आपको एक से अधिक ऑब्जेक्ट्स की क्वेरीसेट के साथ बेहतर प्रदर्शन देगा, क्योंकि यह प्रति क्वेरीसेट में एक डेटाबेस कॉल करेगा।

हालांकि बचत उपयोगी है, क्योंकि आपके मॉडल में सहेजने की विधि को ओवरराइड करना आसान है और वहां अतिरिक्त तर्क जोड़ें। उदाहरण के लिए अपने स्वयं के आवेदन में, मैं एक तिथियां अपडेट करता हूं जब अन्य फ़ील्ड बदल जाते हैं।

Class myModel(models.Model): 
    name = models.CharField() 
    date_created = models.DateField() 

    def save(self): 
     if not self.pk : 
      ### we have a newly created object, as the db id is not set 
      self.date_created = datetime.datetime.now() 
     super(myModel , self).save() 
संबंधित मुद्दे