Browse Source

[5.0.x] Fixed #35223 -- Made Model.full_clean() ignore fields with db_default when validating empty values.

Thanks Brian Ibbotson for the report.

Regression in 7414704e88d73dafbcfbb85f9bc54cb6111439d3.

Backport of 1570ef02f34037d32218d463342592debccf915c from main.
Ben Cail 1 year ago
parent
commit
5f07460a67
3 changed files with 26 additions and 2 deletions
  1. 4 1
      django/db/models/base.py
  2. 4 1
      docs/releases/5.0.4.txt
  3. 18 0
      tests/field_defaults/tests.py

+ 4 - 1
django/db/models/base.py

@@ -30,7 +30,7 @@ from django.db.models import NOT_PROVIDED, ExpressionWrapper, IntegerField, Max,
 from django.db.models.constants import LOOKUP_SEP
 from django.db.models.constraints import CheckConstraint, UniqueConstraint
 from django.db.models.deletion import CASCADE, Collector
-from django.db.models.expressions import RawSQL
+from django.db.models.expressions import DatabaseDefault, RawSQL
 from django.db.models.fields.related import (
     ForeignObjectRel,
     OneToOneField,
@@ -1568,6 +1568,9 @@ class Model(AltersData, metaclass=ModelBase):
             raw_value = getattr(self, f.attname)
             if f.blank and raw_value in f.empty_values:
                 continue
+            # Skip validation for empty fields when db_default is used.
+            if isinstance(raw_value, DatabaseDefault):
+                continue
             try:
                 setattr(self, f.attname, f.clean(raw_value, self))
             except ValidationError as e:

+ 4 - 1
docs/releases/5.0.4.txt

@@ -9,4 +9,7 @@ Django 5.0.4 fixes several bugs in 5.0.3.
 Bugfixes
 ========
 
-* ...
+* Fixed a bug in Django 5.0 that caused a crash of ``Model.full_clean()`` on
+  fields with expressions in ``db_default``. As a consequence,
+  ``Model.full_clean()`` no longer validates for empty values in fields with
+  ``db_default`` (:ticket:`35223`).

+ 18 - 0
tests/field_defaults/tests.py

@@ -2,6 +2,7 @@ from datetime import datetime
 from decimal import Decimal
 from math import pi
 
+from django.core.exceptions import ValidationError
 from django.db import connection
 from django.db.models import Case, F, FloatField, Value, When
 from django.db.models.expressions import (
@@ -169,6 +170,23 @@ class DefaultTests(TestCase):
         years = DBDefaultsFunction.objects.values_list("year", flat=True)
         self.assertCountEqual(years, [2000, datetime.now().year])
 
+    def test_full_clean(self):
+        obj = DBArticle()
+        obj.full_clean()
+        obj.save()
+        obj.refresh_from_db()
+        self.assertEqual(obj.headline, "Default headline")
+
+        obj = DBArticle(headline="Other title")
+        obj.full_clean()
+        obj.save()
+        obj.refresh_from_db()
+        self.assertEqual(obj.headline, "Other title")
+
+        obj = DBArticle(headline="")
+        with self.assertRaises(ValidationError):
+            obj.full_clean()
+
 
 class AllowedDefaultTests(SimpleTestCase):
     def test_allowed(self):