Opened 7 weeks ago

Last modified 5 weeks ago

#36518 closed Bug

full_clean crashes on model with both a CheckConstraint and a GeneratedField with a Case expression (possible regression in Django 5.2) — at Initial Version

Reported by: Olivier Dalang Owned by:
Component: Database layer (models, ORM) Version: 5.2
Severity: Release blocker Keywords:
Cc: Olivier Dalang, Mark Gensler, Simon Charette, Mariusz Felisiak Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hello !

I think I ran accross a regression when upgrading the a model containing a CheckConstraint and a GeneratedField (that are unrelated) from Django 5.1 to 5.2.

Below is a simplified case that reproduces the issue.

I found is a similar ticket: https://code.djangoproject.com/ticket/34871 (affecting 4.2 already, and thus not flagged as regression, for a slightly simpler use case).

That ticket links to recent PR which could quite likely has introduced this regression: https://github.com/django/django/pull/19218

I'm not yet familiar with contributing to Django, and fear this is (way) above my level to fix, but please let me know if I can do anything to help fixing this, as it currently prevents us from upgrading.

Cheers !!

Olivier

# models.py

class MyModel(models.Model):
    class Meta:
        constraints = [
            models.CheckConstraint(name="age_valid", check=Q(age__lt=100)),
        ]

    age = models.IntegerField()
    is_old_enough = models.GeneratedField(
        expression=Case(
            When(
                age__gte=18,
                then=Value(True),
            ),
            default=Value(False),
        ),
        db_persist=True,
        output_field=models.BooleanField(),
    )
# tests.py

class MyTests(TestCase):
    def test_fullclean(self):
        bob = MyModel.objects.create(age=17)
        bob.full_clean()

The test succeeds on Django 5.1, but fails on 5.2.

> uv run --with django==5.2.4 manage.py test
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: test_fullclean (myproj.myapp.tests.MyTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/app/myproj/myapp/tests.py", line 8, in test_fullclean
    bob.full_clean()
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/base.py", line 1674, in full_clean
    self.validate_constraints(exclude=exclude)
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/base.py", line 1622, in validate_constraints
    constraint.validate(model_class, self, exclude=exclude, using=using)
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/constraints.py", line 261, in validate
    against = instance._get_field_expression_map(meta=model._meta, exclude=exclude)
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/base.py", line 1372, in _get_field_expression_map
    generated_field.expression.replace_expressions(replacements),
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/expressions.py", line 427, in replace_expressions
    [
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/expressions.py", line 428, in <listcomp>
    expr.replace_expressions(replacements) if expr else None
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/expressions.py", line 427, in replace_expressions
    [
  File "/home/cache/archive-v0/kkaSi9So5gXBgF1hYbu9X/lib/site-packages/django/db/models/expressions.py", line 428, in <listcomp>
    expr.replace_expressions(replacements) if expr else None
AttributeError: 'Q' object has no attribute 'replace_expressions'
----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (errors=1)
Destroying test database for alias 'default'...
> uv run --with django==5.1.11 manage.py test
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK
Destroying test database for alias 'default'...

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top