seleccionar y actualizar el registro de la base de datos con un único conjunto de consultas

139

¿Cómo ejecuto un updatey selectdeclaraciones en el mismo en querysetlugar de tener que hacer dos consultas: una para seleccionar el objeto y otra para actualizar el objeto

El equivalente en SQL sería algo como:

update my_table set field_1 = 'some value' where pk_field = some_value
Juan
fuente

Respuestas:

267

Utilice el método del objeto de conjunto de consultasupdate :

MyModel.objects.filter(pk=some_value).update(field1='some value')
Daniel Roseman
fuente
95
Solo una advertencia justa ... si usa un updatemétodo como este, entonces las señales adjuntas a ese modelo u otras "cosas de código" no se ejecutarán contra los objetos. Solo un puntero de alguien que se quemó :)
DMac the Destroyer
@DMactheDestroyer amigo, gracias por esa valiosa información. Entonces, ¿deberíamos usar la forma más antigua de actualizarlo? (es decir) obtener y guardar?
@aprender bien amigo, todo depende de tu escenario. El updatemétodo es ideal para actualizaciones masivas, pero debe activar una advertencia en su cabeza cuando lo use para revisar cualquier señal adjunta a ese objeto que también deba dispararse manualmente
DMac the Destroyer
3
¿Es posible acceder a la instancia del modelo actual en la función de actualización? comoMyModel.objects.filter(pk=some_value).update(field1=self.data)
Dipak
8
@DipakChandranP Debería hacer una nueva pregunta en lugar de hacer comentarios sobre una de seis años. Pero las expresiones F () probablemente son lo que quieres.
Daniel Roseman
70

Los objetos de la base de datos de Django usan el mismo método save () para crear y cambiar objetos.

obj = Product.objects.get(pk=pk)
obj.name = "some_new_value"
obj.save()

Cómo Django sabe ACTUALIZAR vs. INSERTAR
Si el atributo de clave principal del objeto se establece en un valor que se evalúa como Verdadero (es decir, un valor distinto de Ninguno o la cadena vacía), Django ejecuta una ACTUALIZACIÓN. Si el atributo de clave principal del objeto no está configurado o si la ACTUALIZACIÓN no actualizó nada, Django ejecuta un INSERTAR.

Ref .: https://docs.djangoproject.com/en/1.9/ref/models/instances/

Slipstream
fuente
17

Esta respuesta compara los dos enfoques anteriores. Si desea actualizar muchos objetos en una sola línea, vaya a:

# Approach 1
MyModel.objects.filter(field1='Computer').update(field2='cool')

De lo contrario, tendría que iterar sobre el conjunto de consultas y actualizar objetos individuales:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. El enfoque 1 es más rápido porque solo realiza una consulta a la base de datos, en comparación con el enfoque 2, que realiza consultas de base de datos 'n + 1'. (Para n elementos en el conjunto de consultas)

  2. El primer enfoque hace una consulta db, es decir, ACTUALIZAR, la segunda hace dos: SELECCIONAR y luego ACTUALIZAR.

  3. La compensación es que, supongamos que tiene algún desencadenante, como la actualización updated_ono cualquier campo relacionado, no se activará en la actualización directa, es decir, el enfoque 1.

  4. El enfoque 1 se usa en un conjunto de consultas, por lo que es posible actualizar varios objetos a la vez, no en el caso del enfoque 2.

Pransh Tiwari
fuente
Con respecto a 1. - Creo que el resultado de la consulta se almacena en caché en la primera llamada a la consulta, por lo tanto, en realidad todavía hay una sola llamada a DB.
user2340939
2

¡solo en un caso en las serializercosas, puedes actualizar de una manera muy simple!

my_model_serializer = MyModelSerializer(
    instance=my_model, data=validated_data)
if my_model_serializer.is_valid():

    my_model_serializer.save()

solo en un caso en las formcosas!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()
Jamil Noyda
fuente
Creo que los serializadores son de Djanog Rest Framework y no de Django propiamente dicho.
Code-Apprentice
1
Sí, sin embargo Django formes de Django Proper.
Jamil Noyda