1
0
mirror of https://github.com/django/django.git synced 2025-10-30 00:56:09 +00:00

Fixed #32095 -- Made QuerySet.update_or_create() save only fields passed in defaults or with custom pre_save().

Thanks Florian Apolloner for the initial patch.
This commit is contained in:
sarahboyce
2022-09-27 15:26:02 +02:00
committed by Mariusz Felisiak
parent 1d77b931f7
commit 6cc0f22a73
3 changed files with 47 additions and 2 deletions

View File

@@ -20,7 +20,7 @@ from django.db import (
router,
transaction,
)
from django.db.models import AutoField, DateField, DateTimeField, sql
from django.db.models import AutoField, DateField, DateTimeField, Field, sql
from django.db.models.constants import LOOKUP_SEP, OnConflict
from django.db.models.deletion import Collector
from django.db.models.expressions import Case, F, Ref, Value, When
@@ -963,7 +963,25 @@ class QuerySet:
return obj, created
for k, v in resolve_callables(defaults):
setattr(obj, k, v)
obj.save(using=self.db)
update_fields = set(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):
# Add fields which are set on pre_save(), e.g. auto_now fields.
# This is to maintain backward compatibility as these fields
# are not updated unless explicitly specified in the
# update_fields list.
for field in self.model._meta.local_concrete_fields:
if not (
field.primary_key or field.__class__.pre_save is Field.pre_save
):
update_fields.add(field.name)
if field.name != field.attname:
update_fields.add(field.attname)
obj.save(using=self.db, update_fields=update_fields)
else:
obj.save(using=self.db)
return obj, False
async def aupdate_or_create(self, defaults=None, **kwargs):