Opened 4 days ago
Closed 4 days ago
#36296 closed Bug (duplicate)
Constraint validation of models with generated fields using Q crashes with AttributeError: 'Q' object has no attribute 'replace_expressions'
Description ¶
Given this trivial model
class Foo(models.Model): bar = models.CharField() is_buzz = models.GeneratedField( expression=models.Q(bar="buzz"), output_field=models.BooleanField(), db_persist=True, ) unrelated = models.CharField() class Meta: constraints = [ models.CheckConstraint( name="check_unrelated", condition=models.Q(unrelated="unrelated") ), ]
Running validate_constraints()
will raise an AttributeError (see below)
This was previously working on 5.1, it appears to be cause by the introduction of constraint validation on generated fields themselves in https://github.com/django/django/commit/228128618bd
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../django/django/db/models/base.py:1576: in validate_constraints constraint.validate(model_class, self, exclude=exclude, using=using) ../../django/django/db/models/constraints.py:602: in validate field_expression_map = instance._get_field_expression_map( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <Foo: Foo object (None)>, meta = <Options for Foo>, exclude = set() def _get_field_expression_map(self, meta, exclude=None): if exclude is None: exclude = set() meta = meta or self._meta field_map = {} generated_fields = [] for field in meta.local_concrete_fields: if field.name in exclude: continue if field.generated: if any( ref[0] in exclude for ref in self._get_expr_references(field.expression) ): continue generated_fields.append(field) continue value = getattr(self, field.attname) if not value or not hasattr(value, "resolve_expression"): value = Value(value, field) field_map[field.name] = value if "pk" not in exclude: field_map["pk"] = Value(self.pk, meta.pk) if generated_fields: replacements = {F(name): value for name, value in field_map.items()} for generated_field in generated_fields: field_map[generated_field.name] = ExpressionWrapper( > generated_field.expression.replace_expressions(replacements), generated_field.output_field, ) E AttributeError: 'Q' object has no attribute 'replace_expressions' ../../django/django/db/models/base.py:1326: AttributeError
Change History (2)
comment:1 by , 4 days ago
comment:2 by , 4 days ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Note:
See TracTickets
for help on using tickets.
This relates to #34871 which has a working prototype that implements
Q.replace_expressions
.Note that passing a
Q
toGeneratedFied.expression
was never entirely supported #34805 (as it's not an expression per-se) and passing a lookup instead most likely solves your issue