2012-09-30 4 views
83

Ich möchte einen Tisch mit Django aktualisieren - so etwas wie dies in raw SQL:Wie man mit Django 'bulk update'?

update tbl_name set name = 'foo' where name = 'bar' 

Mein erstes Ergebnis ist das so etwas wie - aber das ist böse, es ist nicht wahr?

list = ModelClass.objects.filter(name = 'bar') 
for obj in list: 
    obj.name = 'foo' 
    obj.save() 

Gibt es einen eleganteren Weg?

+1

Möglicherweise suchen Sie nach Batch-Einsatz. Werfen Sie einen Blick auf http://stackoverflow.com/questions/4294088/accelerate-bulk-insert-using-djangos-orm – Pramod

+0

Ich mag es nicht, neue Daten einzufügen - nur bestehende aktualisieren. – Thomas

+2

Vielleicht mit Hilfe von select_for_update? https://docs.djangoproject.com/de/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update –

Antwort

149

Siehe die Funktion update in der Dokumentation zu django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update.

Kurz gesagt sollten Sie in der Lage sein zu verwenden:

ModelClass.objects.filter(name='bar').update(name="foo") 

Sie können auch F Objekte verwenden, um Dinge wie Inkrementieren Reihen zu tun:

from django.db.models import F 
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1) 

Lesen Sie die Dokumentation: https://docs.djangoproject.com/en/1.9/topics/db/queries/

jedoch Beachten Sie, dass:

  • Dies wird nicht verwendet ModelClass.save Methode (also wenn Sie etwas Logik drin haben wird nicht ausgelöst werden).
  • Es werden keine Djangosignale ausgegeben.
+21

Beachten Sie auch, dass als Folge nicht 'save()', 'DateTimeField' Felder mit verwenden 'auto_now = True' (" modifizierte "Spalten) werden nicht aktualisiert. – Arthur

+2

Aber 'ModelClass.objects.filter (name = 'bar'). Update (name =" foo ")' erfüllt nicht den Zweck der Massenaktualisierung, wenn ich verschiedene Daten für verschiedene IDs habe, wie könnte ich das tun, ohne Schleife zu verwenden ? – Shashank

+0

@shihon Ich bin mir nicht sicher, ob ich dich richtig verstanden habe, aber ich habe der Antwort Beispiel hinzugefügt. –

24

Betrachten Sie django-bulk-update gefunden here on GitHub.

Install: pip install django-bulk-update

implementieren: (Code direkt aus Projekten ReadMe-Datei genommen)

from bulk_update.helper import bulk_update 

random_names = ['Walter', 'The Dude', 'Donny', 'Jesus'] 
people = Person.objects.all() 

for person in people: 
    r = random.randrange(4) 
    person.name = random_names[r] 

bulk_update(people) # updates all columns using the default db 

Update: Wie Marc Punkte in den Kommentaren aus dieser für die Aktualisierung Tausende von Zeilen nicht geeignet ist Einmal. Obwohl es für kleinere Chargen von 10 bis 100 geeignet ist. Die Größe des Stapels, der für Sie geeignet ist, hängt von Ihrer CPU- und Abfragekomplexität ab. Dieses Werkzeug ist mehr wie eine Schubkarre als ein Muldenkipper.

+5

Ich habe versucht, Django-Bulk-Update, und ich persönlich rate davon ab, es zu verwenden. Was es intern tut, ist eine einzelne SQL-Anweisung zu erstellen, die wie folgt aussieht: UPDATE "Tabelle" SET "Feld" = CASE "ID" WHEN% s DANN% s WANN% s DANN% s [...] WHERE ID in (% s,% s, [...]) ;.Für einige Zeilen ist das in Ordnung (wenn Bulk-Updater nicht benötigt wird), aber bei 10.000 ist die Abfrage so komplex, dass Postgres mehr Zeit mit der CPU aufwendet, um die Abfrage zu 100% zu verstehen, als die Zeit, die das Schreiben auf Festplatte spart . –

+0

@MarcGarcia guter Punkt. Ich habe festgestellt, dass viele Entwickler externe Bibliotheken verwenden, ohne ihre Auswirkungen zu kennen. – Dejell

+2

@MarcGarcia Ich stimme nicht zu, dass Massenupdate nicht wertvoll ist und nur wirklich benötigt wird, wenn Tausende von Updates notwendig sind. Es ist aus den von Ihnen genannten Gründen nicht ratsam, 10.000 Zeilen gleichzeitig zu verwenden, aber es ist viel effizienter, 50 Zeilen gleichzeitig zu aktualisieren, als wenn Sie die db mit 50 separaten Aktualisierungsanforderungen erreichen würden. –