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.constants import LOOKUP_SEP
from django.db.models.deletion import CASCADE, Collector
from django.db.models.expressions import DatabaseDefault
from django.db.models.fields.related import (
ForeignObjectRel,
OneToOneField,
@ -1633,6 +1634,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:

View File

@ -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`).

View File

@ -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):