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
Penso che il codice fornito nella domanda non sia molto dimostrativo: chi vuole impostare l'id per il modello? Assumiamo abbiamo bisogno di questo, e abbiamo operazioni simultanee:
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})
Con update_or_create
funzione, dipende da quale filo viene prima, oggetto viene creato e aggiornato con un'eccezione. Questo sarà thread-safe, ma ha evidentemente scarsa utilità: dipende dalle condizioni di gara del valore di SomeModek.objects.get(some__unique_field=1).some_field
potrebbe essere 1 o 2.
Django fornisce oggetti F, in modo che possiamo aggiornare il nostro codice:
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})
Se un altro processo crea l'oggetto tra le due linee, la chiamata create() genererà un'eccezione Integrity. Inoltre non stai impostando l'id nella chiamata create(). – GDorn
Ok, hai ragione, dovrebbe preoccuparsi di IntegrityError. Modifica il codice. – Nik
Ricorda che ciò che hai postato sopra è già nella versione dev dei queryset di django: https://docs.djangoproject.com/en/dev/ref/models/querysets/#update-or-create –