selecione e atualize o registro do banco de dados com um único conjunto de consultas


139

Como executo uma instrução updatee selectno mesmo, em querysetvez de ter que fazer duas consultas: - uma para selecionar o objeto - e outra para atualizar o objeto

O equivalente no SQL seria algo como:

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

Respostas:


267

Use o método de objetoupdate queryset :

MyModel.objects.filter(pk=some_value).update(field1='some value')

95
Apenas um aviso justo ... se você usar o updatemétodo como esse, qualquer sinal anexado a esse modelo ou outro "código" não será executado nos objetos. Apenas um ponteiro de alguém que se queimou:) #
DMac the Destroyer

@DMactheDestroyer cara obrigado por essa informação valiosa. Então devemos usar a maneira mais antiga de atualizá-lo? (ie) obter e salvar?

@ learning bem cara, tudo depende do seu cenário. O updatemétodo é ótimo para atualizações em massa, mas deve desencadear uma advertência em sua cabeça quando você usá-lo de que você precisa rever quaisquer sinais ligados a esse objeto que também pode precisar de ser manualmente disparado
dmac o Destruidor

3
É possível acessar a instância atual do modelo na função de atualização? comoMyModel.objects.filter(pk=some_value).update(field1=self.data)
Dipak 29/06

8
@DipakChandranP Você deve fazer uma nova pergunta em vez de colocar comentários em uma de seis anos. Mas expressões F () provavelmente querem o que você deseja.
Daniel Roseman

70

Os objetos de banco de dados Django usam o mesmo método save () para criar e alterar objetos.

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

Como o Django sabe UPDATE vs. INSERT
Se o atributo de chave primária do objeto estiver definido como um valor avaliado como True (ou seja, um valor diferente de None ou a string vazia), o Django executará um UPDATE. Se o atributo de chave primária do objeto não estiver definido ou se o UPDATE não atualizou nada, o Django executa um INSERT.

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


17

Esta resposta compara as duas abordagens acima. Se você deseja atualizar muitos objetos em uma única linha, vá para:

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

Caso contrário, você teria que percorrer o conjunto de consultas e atualizar objetos individuais:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. A abordagem 1 é mais rápida porque faz apenas uma consulta ao banco de dados, em comparação com a abordagem 2, que realiza consultas 'n + 1'. (Para n itens no conjunto de consultas)

  2. A primeira abordagem faz uma consulta de banco de dados, ou seja, UPDATE, a segunda faz duas: SELECT e UPDATE.

  3. A desvantagem é que, suponha que você tenha acionadores, como atualização updated_onou quaisquer campos relacionados, ele não será acionado na atualização direta, ou seja, na abordagem 1.

  4. A abordagem 1 é usada em um conjunto de consultas, portanto, é possível atualizar vários objetos de uma vez, não no caso da abordagem 2.


Em relação a 1. - Eu acho que o resultado da consulta é armazenado em cache na primeira chamada para consulta, portanto, na verdade, ainda existe apenas uma chamada para o DB.
user2340939 3/06

2

apenas em um caso de serializercoisas, você pode atualizar de uma maneira muito simples!

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

    my_model_serializer.save()

apenas em um caso de formcoisas!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()

Eu acho que os serializadores são do Djanog Rest Framework e não são apropriados para o Django.
Code-Apprentice

1
Sim, no entanto, Django formé do Django Proper.
Jamil Noyda
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.