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}