Opened 4 months ago
Last modified 3 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 , 4 months ago
Description: | modified (diff) |
---|
comment:2 by , 4 months ago
Description: | modified (diff) |
---|
comment:3 by , 4 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:4 by , 4 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