wybierz i zaktualizuj rekord bazy danych za pomocą jednego zestawu zapytań

144

Jak uruchomić instrukcje updatei selectna tym samym, querysetzamiast wykonywać dwa zapytania: - jedno do wybrania obiektu - drugie do zaktualizowania obiektu

Odpowiednik w SQL wyglądałby tak:

update my_table set field_1 = 'some value' where pk_field = some_value
Jan
źródło

Odpowiedzi:

279

Użyj metody obiektuupdate queryset :

MyModel.objects.filter(pk=some_value).update(field1='some value')
Daniel Roseman
źródło
101
Po prostu uczciwe ostrzeżenie ... jeśli użyjesz takiej updatemetody, to wszelkie sygnały dołączone do tego modelu lub inne „elementy kodu” nie będą działać na obiektach. Tylko wskazówka od kogoś, kto się spalił :)
DMac the Destroyer
@DMactheDestroyer stary dzięki za te cenne informacje. W takim razie powinniśmy użyć starszego sposobu aktualizacji? (tj.) dostać i zapisać?
@ Dobrze się uczę stary, wszystko zależy od twojego scenariusza. updateMetoda doskonale nadaje się do aktualizacji masowych, ale powinna wyruszył ostrzeżenie w twojej głowie, gdy używasz go, że trzeba sprawdzić wszystkie sygnały podłączone do tego obiektu, które mogą również muszą być ręcznie opalane
DMAc Niszczyciela
3
Czy można uzyskać dostęp do aktualnej instancji modelu w funkcji aktualizacji? jakMyModel.objects.filter(pk=some_value).update(field1=self.data)
Dipak
8
@DipakChandranP Powinieneś raczej zadać nowe pytanie niż komentować to, które ma sześć lat. Ale wyrażenia F () są prawdopodobnie pożądane.
Daniel Roseman
74

Obiekty bazy danych Django używają tej samej metody save () do tworzenia i zmiany obiektów.

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

Skąd Django wie, że należy ZAKTUALIZOWAĆ a WSTAWIĆ
Jeśli atrybut klucza podstawowego obiektu jest ustawiony na wartość, której wynikiem jest True (tj. Wartość inna niż None lub pusty łańcuch), Django wykonuje UPDATE. Jeśli atrybut klucza podstawowego obiektu nie jest ustawiony lub jeśli UPDATE niczego nie zaktualizował, Django wykonuje INSERT.

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

Strumień
źródło
19

Ta odpowiedź porównuje powyższe dwa podejścia. Jeśli chcesz zaktualizować wiele obiektów w jednej linii, przejdź do:

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

W przeciwnym razie musiałbyś iterować zestaw zapytań i aktualizować poszczególne obiekty:

#Approach 2    
objects = MyModel.objects.filter(field1='Computer')
for obj in objects:
    obj.field2 = 'cool'
    obj.save()
  1. Podejście 1 jest szybsze, ponieważ wykonuje tylko jedno zapytanie do bazy danych, w porównaniu z podejściem 2, które powoduje zapytania do bazy danych „n + 1”. (Dla n pozycji w zestawie zapytań)

  2. Pierwsze podejście powoduje jedno zapytanie o bazę danych, tj. UPDATE, drugie - dwa: SELECT, a następnie UPDATE.

  3. Kompromis polega na tym, że załóżmy, że masz jakiekolwiek wyzwalacze, takie jak aktualizacja updated_onlub inne powiązane pola, nie zostaną one wyzwolone przy bezpośredniej aktualizacji, tj. W podejściu 1.

  4. Podejście 1 jest używane w zestawie zapytań, więc możliwe jest aktualizowanie wielu obiektów jednocześnie, nie w przypadku podejścia 2.

Pransh Tiwari
źródło
Odnośnie 1. - Myślę, że wynik zapytania jest zapisywany w pamięci podręcznej przy pierwszym wywołaniu zapytania, stąd tak naprawdę nadal istnieje tylko jedno wywołanie DB.
user2340939
2

tylko w przypadku serializerrzeczy można zaktualizować w bardzo prosty sposób!

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

    my_model_serializer.save()

tylko w przypadku formrzeczy!

instance = get_object_or_404(MyModel, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
    form.save()
Jamil Noyda
źródło
Myślę, że serializatory pochodzą z Djanog Rest Framework, a nie z właściwego Django.
Code-Apprentice
1
Tak, jednak Django formpochodzi z Django Proper.
Jamil Noyda
0

Jeśli chcesz ustawić nową wartość na podstawie starej wartości pola, wykonaj coś takiego:

update my_table set field_1 = field_1 + 1 where pk_field = some_value

użyj wyrażeń zapytań :

MyModel.objects.filter(pk=some_value).update(field1=F('field1') + 1)

Spowoduje to niepodzielne wykonanie aktualizacji, która używa jednego żądania aktualizacji do bazy danych bez uprzedniego odczytu.

Roman Konoval
źródło
0

Pierwsza metoda

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

2. metoda

q = MyModel.objects.get(pk=some_value)
q.field1 = 'some value'
q.save()

Trzecia metoda

Używając get_object_or_404

q = get_object_or_404(MyModel,pk=some_value)
q.field1 = 'some value'
q.save()

4. metoda

Jeśli potrzebujesz, jeśli pk=some_valueistnieje, updateto inny mądry createnowy za pomocą update_or_create.

MyModel.objects.update_or_create(pk=some_value,defaults={'field1':'some value'})
Riyas Ac
źródło