1
0
mirror of https://github.com/django/django.git synced 2025-10-24 22:26:08 +00:00

Fixed #34280 -- Allowed specifying different field values for create operation in QuerySet.update_or_create().

This commit is contained in:
tschilling
2023-01-30 20:39:15 -06:00
committed by Mariusz Felisiak
parent ecafcaf634
commit c5808470aa
8 changed files with 212 additions and 27 deletions

View File

@@ -926,25 +926,32 @@ class QuerySet(AltersData):
**kwargs,
)
def update_or_create(self, defaults=None, **kwargs):
def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
"""
Look up an object with the given kwargs, updating one with defaults
if it exists, otherwise create a new one.
if it exists, otherwise create a new one. Optionally, an object can
be created with different values than defaults by using
create_defaults.
Return a tuple (object, created), where created is a boolean
specifying whether an object was created.
"""
defaults = defaults or {}
if create_defaults is None:
update_defaults = create_defaults = defaults or {}
else:
update_defaults = defaults or {}
self._for_write = True
with transaction.atomic(using=self.db):
# 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)
obj, created = self.select_for_update().get_or_create(
create_defaults, **kwargs
)
if created:
return obj, created
for k, v in resolve_callables(defaults):
for k, v in resolve_callables(update_defaults):
setattr(obj, k, v)
update_fields = set(defaults)
update_fields = set(update_defaults)
concrete_field_names = self.model._meta._non_pk_concrete_field_names
# update_fields does not support non-concrete fields.
if concrete_field_names.issuperset(update_fields):
@@ -964,9 +971,10 @@ class QuerySet(AltersData):
obj.save(using=self.db)
return obj, False
async def aupdate_or_create(self, defaults=None, **kwargs):
async def aupdate_or_create(self, defaults=None, create_defaults=None, **kwargs):
return await sync_to_async(self.update_or_create)(
defaults=defaults,
create_defaults=create_defaults,
**kwargs,
)