1
0
mirror of https://github.com/django/django.git synced 2025-03-12 18:30:48 +00:00

Refs #36075 -- Adjusted MTI handling of _non_pk_concrete_field_names.

Regression in bf7b17d16d3978b2e1cee4a0f7ce8840bd1a8dc4.

Thanks Sage Abdullah for the report.
This commit is contained in:
Simon Charette 2025-01-13 22:04:33 -05:00 committed by Sarah Boyce
parent 161e79d277
commit f07360e808
4 changed files with 21 additions and 8 deletions

View File

@ -874,13 +874,13 @@ class Model(AltersData, metaclass=ModelBase):
update_fields = frozenset(update_fields) update_fields = frozenset(update_fields)
field_names = self._meta._non_pk_concrete_field_names field_names = self._meta._non_pk_concrete_field_names
non_model_fields = update_fields.difference(field_names) not_updatable_fields = update_fields.difference(field_names)
if non_model_fields: if not_updatable_fields:
raise ValueError( raise ValueError(
"The following fields do not exist in this model, are m2m " "The following fields do not exist in this model, are m2m "
"fields, or are non-concrete fields: %s" "fields, primary keys, or are non-concrete fields: %s"
% ", ".join(non_model_fields) % ", ".join(not_updatable_fields)
) )
# If saving to the same database, and this model is deferred, then # If saving to the same database, and this model is deferred, then

View File

@ -1008,8 +1008,11 @@ class Options:
Return a set of the non-pk concrete field names defined on the model. Return a set of the non-pk concrete field names defined on the model.
""" """
names = [] names = []
all_pk_fields = set(self.pk_fields)
for parent in self.all_parents:
all_pk_fields.update(parent._meta.pk_fields)
for field in self.concrete_fields: for field in self.concrete_fields:
if field not in self.pk_fields: if field not in all_pk_fields:
names.append(field.name) names.append(field.name)
if field.name != field.attname: if field.name != field.attname:
names.append(field.attname) names.append(field.attname)

View File

@ -74,7 +74,7 @@ class CompositePKUpdateTests(TestCase):
def test_update_fields_pk_field(self): def test_update_fields_pk_field(self):
msg = ( msg = (
"The following fields do not exist in this model, are m2m fields, " "The following fields do not exist in this model, are m2m fields, "
"or are non-concrete fields: id" "primary keys, or are non-concrete fields: id"
) )
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(ValueError, msg):
self.user_1.save(update_fields=["id"]) self.user_1.save(update_fields=["id"])

View File

@ -7,8 +7,8 @@ from .models import Account, Employee, Person, Profile, ProxyEmployee
class UpdateOnlyFieldsTests(TestCase): class UpdateOnlyFieldsTests(TestCase):
msg = ( msg = (
"The following fields do not exist in this model, are m2m fields, or " "The following fields do not exist in this model, are m2m "
"are non-concrete fields: %s" "fields, primary keys, or are non-concrete fields: %s"
) )
def test_update_fields_basic(self): def test_update_fields_basic(self):
@ -308,3 +308,13 @@ class UpdateOnlyFieldsTests(TestCase):
profile_boss = Profile.objects.create(name="Boss", salary=3000) profile_boss = Profile.objects.create(name="Boss", salary=3000)
with self.assertRaisesMessage(ValueError, self.msg % "non_concrete"): with self.assertRaisesMessage(ValueError, self.msg % "non_concrete"):
profile_boss.save(update_fields=["non_concrete"]) profile_boss.save(update_fields=["non_concrete"])
def test_update_pk_field(self):
person_boss = Person.objects.create(name="Boss", gender="F")
with self.assertRaisesMessage(ValueError, self.msg % "id"):
person_boss.save(update_fields=["id"])
def test_update_inherited_pk_field(self):
employee_boss = Employee.objects.create(name="Boss", gender="F")
with self.assertRaisesMessage(ValueError, self.msg % "id"):
employee_boss.save(update_fields=["id"])