summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander <homm86@gmail.com>2020-08-26 13:26:19 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-08-27 11:46:47 +0200
commit20d38fd75903b58335abd8e7cc576a1f1219a4fa (patch)
tree2e4dce419ece528a9da65db0a56e065d2a773b07
parent1251772cb83aa4106f526fe00738e51c0eb59122 (diff)
Fixed #31947 -- Made QuerySet.update_or_create() reuse get_or_create().
-rw-r--r--django/db/models/query.py46
1 files changed, 17 insertions, 29 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index b39a988ab0..b48d0df9c0 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -573,7 +573,17 @@ class QuerySet:
return self.get(**kwargs), False
except self.model.DoesNotExist:
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):
"""
@@ -585,42 +595,20 @@ class QuerySet:
defaults = defaults or {}
self._for_write = True
with transaction.atomic(using=self.db):
- try:
- obj = self.select_for_update().get(**kwargs)
- except self.model.DoesNotExist:
- params = self._extract_model_params(defaults, **kwargs)
- # Lock the row so that a concurrent update is blocked until
- # after update_or_create() has performed its save.
- obj, created = self._create_object_from_params(kwargs, params, lock=True)
- if created:
- return obj, created
+ # Lock the row so that a concurrent update is blocked until
+ # update_or_create() has performed its save.
+ obj, created = self.select_for_update().get_or_create(defaults, **kwargs)
+ if created:
+ return obj, created
for k, v in resolve_callables(defaults):
setattr(obj, k, v)
obj.save(using=self.db)
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):
"""
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 {}
params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}