2012-09-30 16 views
83

Chciałbym zaktualizować tabelę z Django - coś takiego surowca SQL:Jak zaktualizować zbiorczo za pomocą Django?

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

Mój pierwszy wynik jest coś takiego - ale to przykre, prawda?

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

Czy istnieje bardziej elegancki sposób?

+1

Być może szukasz wsadu wsadowego. Spójrz na http://stackoverflow.com/questions/4294088/accelerate-bulk-insert-using-djangos-orm – Pramod

+0

Nie lubię wstawiać nowych danych - wystarczy zaktualizować istniejące. – Thomas

+2

Może przy pomocy select_for_update? https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update –

Odpowiedz

149

Funkcja dostępna w dokumentacji django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update.

W skrócie powinno być możliwe do użycia:

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

Można również użyć F obiektów robić rzeczy jak zwiększający rzędów:

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

Zobacz dokumentację: https://docs.djangoproject.com/en/1.9/topics/db/queries/

jednak , należy pamiętać, że:

  • To nie będzie używać metody ModelClass.save (więc jeśli masz jakąś logikę wewnątrz, nie zostanie wyzwolona).
  • Żadne sygnały django nie będą emitowane.
+21

Pamiętaj również, że w wyniku nie używania pól 'save()', 'DateTimeField' 'auto_now = True' (" zmodyfikowane "kolumny) nie zostaną zaktualizowane. – Arthur

+2

Ale 'ModelClass.objects.filter (name = 'bar'). Update (name =" foo ")' nie spełnia celu aktualizacji zbiorczej, jeśli mam różne dane dla różnych identyfikatorów, jak mogłem to zrobić bez użycia pętli ? – Shashank

+0

@shihon Nie jestem pewien, czy dobrze cię zrozumiałem, ale dodałem przykład do odpowiedzi. –

24

Rozważ użycie django-bulk-update znalezionych here on GitHub.

Instalacja: pip install django-bulk-update

Wdrożenie: (kod podjęte bezpośrednio z projektów Readme)

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 

Aktualizacja: Jak Marc zwraca uwagę w komentarzach ten nie nadaje się do aktualizacji tysiące wierszy w pewnego razu. Chociaż nadaje się do mniejszych partii od 10 do 100. Rozmiar odpowiedniej partii zależy od złożoności procesora i zapytania. To narzędzie przypomina raczej taczkę niż wywrotkę.

+5

Próbowałem aktualizacji django-bulk i osobiście odradzam jej używanie. Wewnętrznie polega na utworzeniu pojedynczego polecenia SQL, które wygląda tak: UPDATE "table" SET "field" = CASE "id" KIEDY% s THEN% s KIEDY% s THEN% s [...] WHERE id in (% s,% s, [...]) ;.Jest to w porządku dla kilku wierszy (gdy aktualizacja zbiorcza nie jest potrzebna), ale z 10 000, zapytanie jest tak złożone, że postgres spędza więcej czasu z procesorem przy 100% zrozumieniu zapytania, niż czas, w którym zapisuje zapis na dysku . –

+0

@MarcGarcia dobry punkt. Zauważyłem, że wielu programistów używa zewnętrznych bibliotek, nie znając ich wpływu. – Dejell

+2

@MarcGarcia Nie zgadzam się z tym, że aktualizacja zbiorcza nie jest wartościowa i jest potrzebna tylko wtedy, gdy konieczne są tysiące aktualizacji. Użycie go do zrobienia 10.000 wierszy naraz nie jest wskazane z powodów, o których wspomniałeś, ale użycie go do aktualizacji 50 wierszy na raz jest znacznie bardziej wydajne niż trafienie do bazy danych za pomocą 50 oddzielnych żądań aktualizacji. –

Powiązane problemy