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

Thanks Brian Ibbotson for the report.

Regression in 7414704e88.
This commit is contained in:
Ben Cail 2024-03-05 16:36:11 -05:00 committed by Mariusz Felisiak
parent 1669e54965
commit 1570ef02f3
3 changed files with 26 additions and 1 deletions

View File

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

View File

@ -9,4 +9,7 @@ Django 5.0.4 fixes several bugs in 5.0.3.
Bugfixes 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`).

View File

@ -2,6 +2,7 @@ from datetime import datetime
from decimal import Decimal from decimal import Decimal
from math import pi from math import pi
from django.core.exceptions import ValidationError
from django.db import connection from django.db import connection
from django.db.models import Case, F, FloatField, Value, When from django.db.models import Case, F, FloatField, Value, When
from django.db.models.expressions import ( from django.db.models.expressions import (
@ -169,6 +170,23 @@ class DefaultTests(TestCase):
years = DBDefaultsFunction.objects.values_list("year", flat=True) years = DBDefaultsFunction.objects.values_list("year", flat=True)
self.assertCountEqual(years, [2000, datetime.now().year]) 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): class AllowedDefaultTests(SimpleTestCase):
def test_allowed(self): def test_allowed(self):