#36518: full_clean crashes on model with both a CheckConstraint and a
GeneratedField with a Case expression (possible regression in Django 5.2)
-------------------------------------+-------------------------------------
     Reporter:  Olivier Dalang       |                     Type:
                                     |  Uncategorized
       Status:  new                  |                Component:  Database
                                     |  layer (models, ORM)
      Version:  5.2                  |                 Severity:  Normal
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
 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


 {{{#!python
 # 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(),
     )
 }}}


 {{{#!python
 # 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'...
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36518>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019832f8b030-a814f325-2865-4cd3-b960-a7a45bd561cf-000000%40eu-central-1.amazonses.com.

Reply via email to