mirror of
https://github.com/django/django.git
synced 2025-02-28 19:44:35 +00:00
Fixed #31947 -- Made QuerySet.update_or_create() reuse get_or_create().
This commit is contained in:
parent
1251772cb8
commit
20d38fd759
@ -573,7 +573,17 @@ class QuerySet:
|
|||||||
return self.get(**kwargs), False
|
return self.get(**kwargs), False
|
||||||
except self.model.DoesNotExist:
|
except self.model.DoesNotExist:
|
||||||
params = self._extract_model_params(defaults, **kwargs)
|
params = self._extract_model_params(defaults, **kwargs)
|
||||||
return self._create_object_from_params(kwargs, params)
|
# Try to create an object using passed params.
|
||||||
|
try:
|
||||||
|
with transaction.atomic(using=self.db):
|
||||||
|
params = dict(resolve_callables(params))
|
||||||
|
return self.create(**params), True
|
||||||
|
except IntegrityError:
|
||||||
|
try:
|
||||||
|
return self.get(**kwargs), False
|
||||||
|
except self.model.DoesNotExist:
|
||||||
|
pass
|
||||||
|
raise
|
||||||
|
|
||||||
def update_or_create(self, defaults=None, **kwargs):
|
def update_or_create(self, defaults=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -585,42 +595,20 @@ class QuerySet:
|
|||||||
defaults = defaults or {}
|
defaults = defaults or {}
|
||||||
self._for_write = True
|
self._for_write = True
|
||||||
with transaction.atomic(using=self.db):
|
with transaction.atomic(using=self.db):
|
||||||
try:
|
# Lock the row so that a concurrent update is blocked until
|
||||||
obj = self.select_for_update().get(**kwargs)
|
# update_or_create() has performed its save.
|
||||||
except self.model.DoesNotExist:
|
obj, created = self.select_for_update().get_or_create(defaults, **kwargs)
|
||||||
params = self._extract_model_params(defaults, **kwargs)
|
if created:
|
||||||
# Lock the row so that a concurrent update is blocked until
|
return obj, created
|
||||||
# after update_or_create() has performed its save.
|
|
||||||
obj, created = self._create_object_from_params(kwargs, params, lock=True)
|
|
||||||
if created:
|
|
||||||
return obj, created
|
|
||||||
for k, v in resolve_callables(defaults):
|
for k, v in resolve_callables(defaults):
|
||||||
setattr(obj, k, v)
|
setattr(obj, k, v)
|
||||||
obj.save(using=self.db)
|
obj.save(using=self.db)
|
||||||
return obj, False
|
return obj, False
|
||||||
|
|
||||||
def _create_object_from_params(self, lookup, params, lock=False):
|
|
||||||
"""
|
|
||||||
Try to create an object using passed params. Used by get_or_create()
|
|
||||||
and update_or_create().
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with transaction.atomic(using=self.db):
|
|
||||||
params = dict(resolve_callables(params))
|
|
||||||
obj = self.create(**params)
|
|
||||||
return obj, True
|
|
||||||
except IntegrityError:
|
|
||||||
try:
|
|
||||||
qs = self.select_for_update() if lock else self
|
|
||||||
return qs.get(**lookup), False
|
|
||||||
except self.model.DoesNotExist:
|
|
||||||
pass
|
|
||||||
raise
|
|
||||||
|
|
||||||
def _extract_model_params(self, defaults, **kwargs):
|
def _extract_model_params(self, defaults, **kwargs):
|
||||||
"""
|
"""
|
||||||
Prepare `params` for creating a model instance based on the given
|
Prepare `params` for creating a model instance based on the given
|
||||||
kwargs; for use by get_or_create() and update_or_create().
|
kwargs; for use by get_or_create().
|
||||||
"""
|
"""
|
||||||
defaults = defaults or {}
|
defaults = defaults or {}
|
||||||
params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
|
params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user