Opened 7 months ago
Closed 7 months ago
#36296 closed Bug (duplicate)
Constraint validation of models with generated fields using Q crashes with AttributeError: 'Q' object has no attribute 'replace_expressions'
| Reported by: | David Sanders | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
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 , 7 months ago
comment:2 by , 7 months 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
QtoGeneratedFied.expressionwas never entirely supported #34805 (as it's not an expression per-se) and passing a lookup instead most likely solves your issue