Dzwonię.update() na pojedynczej instancji modelu pobranej przez.get()?

Mam funkcję, która aktualnie wywołuje Models.object.get(), która zwraca 0 LUB 1 obiekt modelu. Jeśli zwróci 0, utworzę nową instancję modelu w klauzuli except DoesNotExist funkcji. W przeciwnym razie chciałbym zaktualizować pola w istniejącej instancji, bez tworzenia nowej. Początkowo próbowałem wywołać .update() na instancji, która została znaleziona, ale .update() wydaje się być możliwe tylko wywołanie na QuerySets. Jak ominąć zmianę kilkunastu pól, bez wywoływania .filter() i porównywania ile chcesz wiedzieć, czy muszę utworzyć lub zaktualizować istniejącą już instancję?

Author: Daniel H., 2012-09-12

6 answers

Wraz z pojawieniem się Django 1.7, pojawiła się nowa update_or_create QuerySet metoda, która powinna zrobić dokładnie to, co chcesz. Tylko uważaj na potencjalne warunki wyścigu, jeśli unikalność nie jest wymuszana na poziomie bazy danych.

Przykład z dokumentacji:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values)

Pre-Django 1.7:

Zmień odpowiednio wartości pola Modelu, a następnie wywołaj .save(), aby utrzymać zmiany:

try:
    obj = Model.objects.get(field=value)
    obj.field = new_value
    obj.save()
except Model.DoesNotExist:
    obj = Model.objects.create(field=new_value)
# do something else with obj if need be
 39
Author: Platinum Azure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-11 20:37:29

Od Django 1.5 istnieje właściwość update_fields na modelu save. eg:

obj.save(update_fields=['field1', 'field2', ...])

Https://docs.djangoproject.com/en/dev/ref/models/instances/

Preferuję to podejście, ponieważ nie tworzy problemu atomiczności, jeśli wiele instancji aplikacji Web zmienia różne części instancji modelu.

 33
Author: Nils,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-10 06:25:30

Nie wiem jak to jest dobre czy złe, ale możesz spróbować czegoś takiego:

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()
 18
Author: Rohan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-12 05:49:22

Jeśli chcesz tylko zaktualizować model, jeśli istnieje (bez tworzenia GO):

Model.objects.filter(id = 223).update(field1 = 2)

Zapytanie Mysql:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
 18
Author: Eyal Ch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 15:15:56

Oto mixin, który możesz mieszać do dowolnej klasy modelu, która daje każdej instancji metodę update:

class UpdateMixin(object):
    def update(self, **kwargs):
        if self._state.adding:
            raise self.DoesNotExist
        for field, value in kwargs.items():
            setattr(self, field, value)
        self.save(update_fields=kwargs.keys())

Kontrola self._state.adding sprawdza, czy model jest zapisany w bazie danych, a jeśli nie, wyświetla błąd.

(Uwaga: ta metoda update jest przeznaczona, gdy chcesz zaktualizować model i wiesz, że instancja jest już zapisana w bazie danych, odpowiadając bezpośrednio na oryginalne pytanie. Wbudowana metoda update_or_create w odpowiedzi Platinum Azure obejmuje już drugą przypadek użycia.)

Użyłbyś go w ten sposób (po zmieszaniu tego z modelem użytkownika):

user = request.user
user.update(favorite_food="ramen")

Oprócz ładniejszego API, kolejną zaletą tego podejścia jest to, że wywołuje Hooki pre_save i post_save, jednocześnie unikając problemów z atomicznością, jeśli inny proces aktualizuje ten sam model.

 5
Author: Julien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-21 17:53:32

W takich przypadkach używam następującego kodu:

obj, created = Model.objects.get_or_create(id=some_id)

if not created:
   resp= "It was created"
else:
   resp= "OK"
   obj.save()
 0
Author: Aragon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-12 07:28:17