2012-09-30 23 views
83

me gustaría actualizar una tabla con Django - algo como esto en SQL prima:¿Cómo 'actualizar a granel' con Django?

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

Mi primer resultado es algo como esto - pero eso es desagradable, ¿verdad?

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

¿Hay una manera más elegante?

+1

Quizás esté buscando por lotes. Eche un vistazo a http://stackoverflow.com/questions/4294088/accelerate-bulk-insert-using-djangos-orm – Pramod

+0

No me gusta insertar datos nuevos, simplemente actualice los existentes. – Thomas

+2

¿Quizás con la ayuda de select_for_update? https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update –

Respuesta

149

Consulte la función update en la documentación de django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update.

En resumen usted debe ser capaz de utilizar:

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

También puede utilizar F objetos para hacer cosas como filas de incremento:

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

Consulte la documentación: https://docs.djangoproject.com/en/1.9/topics/db/queries/

Sin embargo , tenga en cuenta que:

  • Esto no usará el método ModelClass.save (por lo tanto, si tiene alguna lógica interna, no se activará).
  • No se emitirán señales django.
+21

Tenga en cuenta también que como consecuencia de no utilizar los campos 'save()', 'DateTimeField' con 'auto_now = True' (columnas" modificadas ") no se actualizará. – Arthur

+2

Pero 'ModelClass.objects.filter (name = 'bar'). Update (name =" foo ")' no cumple el propósito de la actualización masiva, si tengo datos diferentes para diferentes identificadores, ¿cómo podría hacerlo sin usar el bucle? ? – Shashank

+0

@shihon No estoy seguro de si te entendí bien, pero agregué un ejemplo a la respuesta. –

24

Considerar el uso de django-bulk-update encontrado here on GitHub.

Instalar: pip install django-bulk-update

Implementar: (código tomado directamente de los proyectos archivo Léeme)

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 

Actualización: Como Marc señala en los comentarios esto no es apto para la actualización de miles de filas en una vez. Aunque es adecuado para lotes más pequeños de 10 a 100. El tamaño del lote adecuado para usted depende de su CPU y de la complejidad de la consulta. Esta herramienta es más como una carretilla de ruedas que un camión de volteo.

+5

Probé django-bulk-update, y personalmente desaconsejo su uso. Lo que hace internamente es crear una sola instrucción SQL que se vea así: ACTUALIZAR "tabla" SET "campo" = CASE "id" CUANDO% s THEN% s CUANDO% s THEN% s [...] DONDE id (% s,% s, [...]) ;.Esto está bien para algunas filas (cuando no se necesita el actualizador masivo), pero con 10,000, la consulta es tan compleja, que postgres pasa más tiempo con la CPU al 100% entendiendo la consulta, que el tiempo que ahorra escribir en el disco . –

+0

@MarcGarcia buen punto. Encontré que muchos desarrolladores utilizan bibliotecas externas sin conocer su impacto – Dejell

+2

@MarcGarcia No estoy de acuerdo con que la actualización masiva no sea valiosa y solo realmente necesaria cuando se necesitan miles de actualizaciones. Usarlo para hacer 10,000 filas a la vez no es aconsejable por las razones que mencionaste, pero usarlo para actualizar 50 filas a la vez es mucho más eficiente que presionar el archivo base con 50 solicitudes de actualización separadas. –

Cuestiones relacionadas