2012-09-30 13 views
83

vorrei aggiornare una tabella con Django - qualcosa di simile in SQL prime:Come eseguire il "bulk update" con Django?

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

mio primo risultato è qualcosa di simile - ma questo è brutto, non è vero?

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

C'è un modo più elegante?

+1

Si potrebbe cercare inserto batch. Dai un'occhiata a http://stackoverflow.com/questions/4294088/accelerate-bulk-insert-using-djangos-orm – Pramod

+0

Non mi piace inserire nuovi dati - basta aggiornare esistenti. – Thomas

+2

Forse con l'aiuto di select_for_update? https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update –

risposta

149

Fare riferimento alla funzione update nella documentazione di django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update.

In breve si dovrebbe essere in grado di utilizzare:

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

È inoltre possibile utilizzare F oggetti per fare le cose come le righe incrementali:

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

Vedere la documentazione: https://docs.djangoproject.com/en/1.9/topics/db/queries/

Tuttavia , notare che:

  • Questo non utilizzerà il metodo ModelClass.save (quindi se si dispone di una logica al suo interno non verrà attivato).
  • Nessun segnale di Django verrà emesso.
+21

Nota anche che come conseguenza di non usare i campi 'save()', 'DateTimeField' con 'auto_now = True' (colonne" modificate ") non verranno aggiornate. – Arthur

+2

Ma 'ModelClass.objects.filter (name = 'bar'). Update (name =" foo ")' non soddisfa lo scopo di aggiornamento in blocco, se ho dati diversi per id differenti come posso farlo senza usare il ciclo ? – Shashank

+0

@shihon Non sono sicuro se ti ho capito bene, ma ho aggiunto un esempio alla risposta. –

24

Considerare l'utilizzo di django-bulk-update trovato here on GitHub.

Installare: pip install django-bulk-update

Implementare: (codice preso direttamente dal file Leggimi progetti)

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 

Aggiornamento: Come Marc sottolinea nei commenti questo non è adatto per l'aggiornamento migliaia di righe alla una volta. Anche se è adatto per piccoli lotti da 10 a 100's. La dimensione del batch giusto per te dipende dalla tua CPU e dalla complessità della query. Questo strumento è più simile a una carriola rispetto a un autocarro con cassone ribaltabile.

+5

Ho provato django-bulk-update e personalmente sconsiglio di usarlo. Quello che fa internamente è creare una singola istruzione SQL che assomigli a questo: UPDATE "tabella" SET "campo" = CASE "id" QUANDO% s ALLORA% s QUANDO% s ALL'INIZIO% s [...] WHERE id in (% s,% s, [...]) ;.Questo è abbastanza buono per poche righe (quando non è necessario l'aggiornamento cumulativo), ma con 10.000, la query è così complessa, che postgres passa più tempo con la CPU al 100% a capire la query, rispetto al tempo in cui salva la scrittura sul disco . –

+0

@MarcGarcia buon punto. Ho trovato che molti sviluppatori usano librerie esterne senza conoscerne l'impatto – Dejell

+2

@MarcGarcia Non sono d'accordo che l'aggiornamento collettivo non è prezioso e serve solo quando sono necessari migliaia di aggiornamenti. Usarlo per fare 10.000 file alla volta non è consigliabile per i motivi che hai menzionato, ma usarlo per aggiornare 50 righe contemporaneamente è molto più efficiente di colpire il db con 50 richieste di aggiornamento separate. –