diff --git a/django/db/models/base.py b/django/db/models/base.py index c3f6b32a5e..1e47ca7d1d 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1561,7 +1561,7 @@ class Model(AltersData, metaclass=ModelBase): errors = {} for f in self._meta.fields: - if f.name in exclude: + if f.name in exclude or f.generated: continue # Skip validation for empty fields with blank=True. The developer # is responsible for making sure they have a valid value. diff --git a/docs/releases/5.0.2.txt b/docs/releases/5.0.2.txt index a5e2b6eee4..05f80bb00f 100644 --- a/docs/releases/5.0.2.txt +++ b/docs/releases/5.0.2.txt @@ -15,3 +15,6 @@ Bugfixes * Fixed a regression in Django 5.0 where links in the admin had an incorrect color (:ticket:`35121`). + +* Fixed a bug in Django 5.0 that caused a crash of ``Model.full_clean()`` on + models with a ``GeneratedField`` (:ticket:`35127`). diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index 69b4e26145..e34f3c8947 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -502,7 +502,7 @@ class GeneratedModel(models.Model): output_field=models.IntegerField(), db_persist=True, ) - fk = models.ForeignKey(Foo, on_delete=models.CASCADE, null=True) + fk = models.ForeignKey(Foo, on_delete=models.CASCADE, null=True, blank=True) class Meta: required_db_features = {"supports_stored_generated_columns"} @@ -516,7 +516,7 @@ class GeneratedModelVirtual(models.Model): output_field=models.IntegerField(), db_persist=False, ) - fk = models.ForeignKey(Foo, on_delete=models.CASCADE, null=True) + fk = models.ForeignKey(Foo, on_delete=models.CASCADE, null=True, blank=True) class Meta: required_db_features = {"supports_virtual_generated_columns"} diff --git a/tests/model_fields/test_generatedfield.py b/tests/model_fields/test_generatedfield.py index 589f78cbb0..a636e984fd 100644 --- a/tests/model_fields/test_generatedfield.py +++ b/tests/model_fields/test_generatedfield.py @@ -168,6 +168,14 @@ class GeneratedFieldTestMixin: with self.assertRaisesMessage(AttributeError, msg): m.field + def test_full_clean(self): + m = self.base_model(a=1, b=2) + # full_clean() ignores GeneratedFields. + m.full_clean() + m.save() + m = self._refresh_if_needed(m) + self.assertEqual(m.field, 3) + def test_create(self): m = self.base_model.objects.create(a=1, b=2) m = self._refresh_if_needed(m)