2015-05-26 10 views
13

Ich schreibe eine Django-App, und ich brauche eine Funktion, um ein Feld in der Datenbank zu aktualisieren. Gibt es einen Grund, eine dieser Methoden anstelle der anderen zu machen?Django: save() vs update() um die Datenbank zu aktualisieren?

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) 

Es scheint wie die zweite ist besser, weil es es in einem DB-Aufruf statt zwei tut. Gibt es einen Grund, warum das Holen, dann das Aktualisieren besser ist?

+1

möglich Duplikat [Mit QuerySet.update() im Vergleich zu ModelInstance.save() in Django] (http://stackoverflow.com/questions/4519336/using-queryset-update-versus-modelinstance-save- in-django) – sobolevn

+1

@Sobolevn diese Frage und Antworten sind ziemlich veraltet, seit Django war in der Version 1.0 oder 1.1 oder so ähnlich. Diese Verisons sind veraltet und werden nicht mehr unterstützt, da im Laufe der Zeit viele Änderungen vorgenommen wurden. – FallenAngel

+0

@FallenAngel, yeah, ich habe das Datum zuerst gesehen. Aber als ich es herausgefunden habe, gab ich eine Antwort. – sobolevn

Antwort

14

Es gibt einige wichtige Unterschiede.

update wird in einem Abfrage-Set verwendet, daher ist es möglich, mehrere Objekte gleichzeitig zu aktualisieren.

Wie @FallenAngel darauf hingewiesen, gibt es Unterschiede, wie benutzerdefinierten save() Methode auslöst, aber es ist auch wichtig, im Auge zu behalten signals und ModelManagers. Ich habe eine kleine Test-App gebaut, um einige wertvolle Unterschiede zu zeigen. Ich benutze Python 2.7.5, Django == 1.7.7 und SQLite, beachten Sie, dass die endgültigen SQLs auf verschiedenen Versionen von Django und verschiedenen Datenbank-Engines variieren können.

Ok, hier ist der Beispielcode.

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 

, die in diesen SQL-Abfragen 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') 

Wir haben nur eine Abfrage für update() und zwei für save().

Als nächstes sprechen wir über das Überschreiben save() Methode. Es wird nur einmal offensichtlich für save() Methode aufgerufen. Es ist erwähnenswert, dass .objects.create() ruft auch save() Methode.

Aber update() ruft save() auf Modellen nicht auf. Und wenn für update() keine save() Methode aufgerufen wird, werden auch die Signale nicht ausgelöst. Ausgang:

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>] 

Wie Sie save() löst Manager ‚s get_queryset() zweimal sehen. Wenn update() nur einmal.

Auflösung. Wenn Sie Ihre Werte "stumm" aktualisieren müssen, ohne save() aufgerufen zu haben - verwenden Sie update. Anwendungsfälle: last_seen Benutzerfeld. Wenn Sie Ihr Modell ordnungsgemäß aktualisieren müssen, verwenden Sie save().

2

Die Methode save() kann verwendet werden, um einen neuen Datensatz einzufügen und einen vorhandenen Datensatz zu aktualisieren, und wird normalerweise zum Speichern einer Instanz eines einzelnen Datensatzes (Zeile in MySQL) in der Datenbank verwendet.

update() wird nicht zum Einfügen von Datensätzen verwendet und kann zum Aktualisieren mehrerer Datensätze (Zeilen in MySQL) in der Datenbank verwendet werden.

2

Das Update funktioniert nur beim Aktualisieren von Abfragesätzen. Wenn Sie mehrere Felder gleichzeitig aktualisieren möchten, sagen wir von einem dict für ein einzelnes Objekt Instanz, die Sie so etwas wie tun:

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

Beachten Sie, dass Ihr Wörterbuch muss die korrekte Zuordnung enthalten, wo die Tasten müssen Ihre Feldnamen und die Werte die Werte sein, die Sie einfügen möchten.

11

sieht Beide ähnlich, aber es gibt einige wichtige Punkte:

  1. save() löst jede Model.save() Methode überschrieben, aber update() wird dies nicht auslösen und eine direkte Aktualisierung auf Datenbankebene machen. Wenn Sie also einige Modelle mit überschriebenen Speichermethoden haben, müssen Sie entweder die Verwendung von update vermeiden oder einen anderen Weg finden, um das zu tun, was Sie auf diesen überschriebenen save() Methoden tun.

  2. obj.save() kann einige Nebenwirkungen haben, wenn Sie nicht vorsichtig sind. Sie rufen das Objekt mit get(...) ab und alle Modellfeldwerte werden an Ihr Objekt übergeben. Wenn Sie obj.save() aufrufen, speichert Django den aktuellen Objektstatus für die Aufzeichnung. Wenn also zwischen get() und save() durch einen anderen Prozess Änderungen vorgenommen werden, gehen diese Änderungen verloren. Verwenden Sie save(update_fields=[.....]), um solche Probleme zu vermeiden.

  3. Vor Django Version 1.5, führte Django eine SELECT vor INSERT/UPDATE, so kostet es 2 Abfrage Ausführung. Mit Version 1.5 ist diese Methode veraltet.

In here, gibt es eine gute Anleitung oder save() und update() Methoden und wie sie ausgeführt werden.

2

Update wird Ihnen eine bessere Leistung mit einem Abfrage-Set von mehr als einem Objekt bieten, da es einen Datenbank-Aufruf pro Abfrage-Set machen wird.

Speichern ist jedoch nützlich, da es einfach ist, die Speichermethode in Ihrem Modell zu überschreiben und zusätzliche Logik hinzuzufügen. In meiner eigenen Anwendung beispielsweise aktualisiere ich ein Datum, wenn andere Felder geändert werden.

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() 
Verwandte Themen