from django.db import IntegrityError
def update_or_create(model, filter_kwargs, update_kwargs)
if not model.objects.filter(**filter_kwargs).update(**update_kwargs):
kwargs = filter_kwargs.copy()
kwargs.update(update_kwargs)
try:
model.objects.create(**kwargs)
except IntegrityError:
if not model.objects.filter(**filter_kwargs).update(**update_kwargs):
raise # re-raise IntegrityError
Я думаю, что код, представленный в вопросе, не очень показателен: кто хочет установить id для модели? Давайте предположим, что нам это нужно, и мы одновременно операции:
def thread1():
update_or_create(SomeModel, {'some_unique_field':1}, {'some_field': 1})
def thread2():
update_or_create(SomeModel, {'some_unique_field':1}, {'some_field': 2})
С update_or_create
функция, зависит от того, какой поток приходит первым, объект будет создан и обновляется без исключения. Это будет потокобезопасной, но, очевидно, имеет мало пользы: зависит от состояния гонки стоимости SomeModek.objects.get(some__unique_field=1).some_field
может быть 1 или 2.
Django предоставляет объекты F, так что мы можем обновить наш код:
from django.db.models import F
def thread1():
update_or_create(SomeModel,
{'some_unique_field':1},
{'some_field': F('some_field') + 1})
def thread2():
update_or_create(SomeModel,
{'some_unique_field':1},
{'some_field': F('some_field') + 2})
Если другой процесс создает объект между двумя строками, вызов create() вызовет IntegrityError. Вы также не устанавливаете идентификатор в вызове create(). – GDorn
Хорошо, вы должны заботиться о IntegrityError. Будет редактировать код. – Nik
Имейте в виду, что то, что вы разместили выше, уже находится в dev-версии наборов запросов django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update-or-create –