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 cannot be used " - "in an ORM query." + "Cannot update model field (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 " + "(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 " + "(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 " + "(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)