summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan P Kilby <kilbyr@gmail.com>2025-06-25 22:54:50 -0700
committerJacob Walls <jacobtylerwalls@gmail.com>2025-09-04 12:15:45 -0400
commitbad03eb108b029dad70cbd997f1fef221da3e415 (patch)
treee446cd695bada7986c5b9b5c4a44bbdf0759677e
parent11c2c9ac17db1c04c6de302167d4b0a5539c90fd (diff)
Fixed #36481 -- Fixed QuerySet.update concrete fields check.
FieldError is now emitted for invalid update calls involving reverse relations, where previously they failed with AttributeError.
-rw-r--r--django/db/models/sql/subqueries.py5
-rw-r--r--tests/composite_pk/test_update.py11
-rw-r--r--tests/update/models.py3
-rw-r--r--tests/update/tests.py24
4 files changed, 35 insertions, 8 deletions
diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py
index 2705114a54..9936f7ff42 100644
--- a/django/db/models/sql/subqueries.py
+++ b/django/db/models/sql/subqueries.py
@@ -87,15 +87,12 @@ class UpdateQuery(Query):
values_seq = []
for name, val in values.items():
field = self.get_meta().get_field(name)
- direct = (
- not (field.auto_created and not field.concrete) or not field.concrete
- )
model = field.model._meta.concrete_model
if field.name == "pk" and model._meta.is_composite_pk:
raise FieldError(
"Composite primary key fields must be updated individually."
)
- if not direct or (field.is_relation and field.many_to_many):
+ if not field.concrete or (field.is_relation and field.many_to_many):
raise FieldError(
"Cannot update model field %r (only non-relations and "
"foreign keys permitted)." % field
diff --git a/tests/composite_pk/test_update.py b/tests/composite_pk/test_update.py
index 697383b007..8d786e8afb 100644
--- a/tests/composite_pk/test_update.py
+++ b/tests/composite_pk/test_update.py
@@ -169,13 +169,16 @@ class CompositePKUpdateTests(TestCase):
token_3 = Token.objects.get(pk=self.token_3.pk)
self.assertEqual(token_3.secret, "bar")
- def test_cant_update_to_unsaved_object(self):
+ def test_cant_update_relation(self):
msg = (
- "Unsaved model instance <User: User object ((None, None))> cannot be used "
- "in an ORM query."
+ "Cannot update model field <django.db.models.fields.related.ForeignObject: "
+ "user> (only non-relations and foreign keys permitted)"
)
- with self.assertRaisesMessage(ValueError, msg):
+ with self.assertRaisesMessage(FieldError, msg):
+ Comment.objects.update(user=self.user_1)
+
+ with self.assertRaisesMessage(FieldError, msg):
Comment.objects.update(user=User())
def test_cant_update_pk_field(self):
diff --git a/tests/update/models.py b/tests/update/models.py
index d71fc887c7..3d93915c9f 100644
--- a/tests/update/models.py
+++ b/tests/update/models.py
@@ -41,6 +41,9 @@ class Foo(models.Model):
class Bar(models.Model):
foo = models.ForeignKey(Foo, models.CASCADE, to_field="target")
+ o2o_foo = models.OneToOneField(
+ Foo, models.CASCADE, related_name="o2o_bar", null=True
+ )
m2m_foo = models.ManyToManyField(Foo, related_name="m2m_foo")
x = models.IntegerField(default=0)
diff --git a/tests/update/tests.py b/tests/update/tests.py
index fdd0631142..af5939a2ef 100644
--- a/tests/update/tests.py
+++ b/tests/update/tests.py
@@ -173,6 +173,30 @@ class AdvancedTests(TestCase):
with self.assertRaisesMessage(FieldError, msg):
Foo.objects.update(m2m_foo="whatever")
+ def test_update_reverse_fk_descriptor(self):
+ msg = (
+ "Cannot update model field <ManyToOneRel: update.bar> "
+ "(only non-relations and foreign keys permitted)."
+ )
+ with self.assertRaisesMessage(FieldError, msg):
+ Foo.objects.update(bar="whatever")
+
+ def test_update_reverse_o2o_descriptor(self):
+ msg = (
+ "Cannot update model field <OneToOneRel: update.bar> "
+ "(only non-relations and foreign keys permitted)."
+ )
+ with self.assertRaisesMessage(FieldError, msg):
+ Foo.objects.update(o2o_bar="whatever")
+
+ def test_update_reverse_mti_parent_link_descriptor(self):
+ msg = (
+ "Cannot update model field <OneToOneRel: update.uniquenumberchild> "
+ "(only non-relations and foreign keys permitted)."
+ )
+ with self.assertRaisesMessage(FieldError, msg):
+ UniqueNumber.objects.update(uniquenumberchild="whatever")
+
def test_update_transformed_field(self):
A.objects.create(x=5)
A.objects.create(x=-6)