Opened 6 months ago
Last modified 5 months ago
#36352 assigned Cleanup/optimization
Weird behavior of .values after a distinct in 5.1.8 — at Version 4
| Reported by: | Joseph Yu | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.0 |
| Severity: | Normal | Keywords: | .values, distinct |
| Cc: | Joseph Yu, Simon Charette | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | yes |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Was upgrading from 4.2.20 to 5.1.8 when tests were failing with a certain query in our app.
Models:
class Foo(models.Model):
name = models.CharField(max_length=255)
class Mapping(models.Model):
field = models.CharField(max_length=255)
foo = models.ForeignKey(Foo, null=True, blank=True, on_delete=models.PROTECT)
class Tenant(TenantMixin):
created_at = models.DateField(auto_now_add=True)
mapping = models.ForeignKey(Mapping, null=True, blank=True, on_delete=models.PROTECT)
Code:
a = Mapping.objects.filter(id=1).values('id').annotate(foo=F('foo__name'),foo_id=F('foo_id'))
b = Mapping.objects.filter(id=2).values('id').annotate(foo=F('foo__name'),foo_id=F('foo_id'))
c = (a|b).distinct()
d = c.filter(id=OuterRef('mapping_id')).values('foo')
e = Tenant.objects.values('id').annotate(foo_id=Subquery(d.values('foo_id')))
This throws an error in 5.1.8:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/user/.pyenv/versions/3.13.0/lib/python3.13/site-packages/django/db/models/query.py", line 1360, in values
clone = self._values(*fields, **expressions)
File "/Users/user/.pyenv/versions/3.13.0/lib/python3.13/site-packages/django/db/models/query.py", line 1355, in _values
clone.query.set_values(fields)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/Users/user/.pyenv/versions/3.13.0/lib/python3.13/site-packages/django/db/models/sql/query.py", line 2462, in set_values
raise FieldError(
...<2 lines>...
)
django.core.exceptions.FieldError: Cannot select the 'foo_id' alias. Use annotate() to promote it.
Current workaround is to include the annotated field in .values like so
d = c.filter(id=OuterRef('mapping_id')).values('foo', 'foo_id')
e = Tenant.objects.values('id').annotate(foo_id=Subquery(d.values('foo_id')))
Change History (4)
comment:1 by , 6 months ago
| Description: | modified (diff) |
|---|
comment:2 by , 6 months ago
| Description: | modified (diff) |
|---|
comment:3 by , 6 months ago
| Resolution: | → needsinfo |
|---|---|
| Status: | new → closed |
comment:4 by , 6 months ago
| Description: | modified (diff) |
|---|---|
| Resolution: | needsinfo |
| Status: | closed → new |
Note:
See TracTickets
for help on using tickets.
So yes this fails, but it seems to fail in Django 4.2 as well. It might help sharing the model as well. It would also be useful to do a git bisect to identify when this started failing