Opened 3 weeks ago

Last modified 2 weeks ago

#37308 assigned Cleanup/optimization

Lookups on annotation aliases in .values() and .order_by() resolve unexpectedly

Reported by: Annabelle Wiegart Owned by: Dinesh Thumma
Component: Database layer (models, ORM) Version: 6.1
Severity: Normal Keywords: alias, values, order_by
Cc: Annabelle Wiegart Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Doing a lookup on an annotation alias results in an unexpected name resolution. When calling e.g. .values(alias + "__pk"), Query.names_to_path() checks if f"{alias}__pk" is the name of an annotation. Otherwise it tries to resolve the name into field plus lookup. This might be unexpected. While allowing lookups on aliases may add too much complexity and therefore not be desirable, it would probably be helpful to at least show a warning when .values() or .order_by() is called on an expression containing an alias name and __.

The issue has been discussed in PR21803 for #36945.

ORM fiddle

Reproducer:

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType


class Person(models.Model):
    name = models.CharField(max_length=100)
    creator = models.ForeignKey(User, models.CASCADE, null=True)
    ct = models.ForeignKey(ContentType, models.CASCADE)


def run():
    admin = User.objects.create(username='admin')
    person_ct = ContentType.objects.get_for_model(Person)
    Person.objects.create(creator=admin, name="Claude", ct=person_ct)
    # resolves correctly
    qs1 = Person.objects.all().values("creator__pk")
    print(qs1)
    
    alias = "myalias"
    # raises FieldError
    qs2 = Person.objects.annotate(**{alias: models.F("creator")}).values(alias + "__pk")
    print(qs2)
    # raises FieldError
    qs3 = Person.objects.annotate(
        **{alias: models.FilteredRelation("creator", condition=models.Q(creator__isnull=False))}
    ).values(alias + "__pk")
    print(qs3)

Output:

django.core.exceptions.FieldError: Cannot resolve keyword 'myalias' into field. Choices are: creator, creator_id, ct, ct_id, id, name

Change History (5)

comment:1 by Annabelle Wiegart, 3 weeks ago

Type: UncategorizedCleanup/optimization

comment:2 by Jacob Walls, 3 weeks ago

Triage Stage: UnreviewedAccepted

Maybe we should retry by splitting on the separator from right to left, e.g. for a__b__c, try a__b__c, then a__b + c (lookup), then a + b__c (transform/lookup).

comment:3 by Zubair Hassan, 3 weeks ago

Owner: set to Zubair Hassan
Status: newassigned

comment:4 by Zubair Hassan, 2 weeks ago

Owner: Zubair Hassan removed
Status: assignednew

comment:5 by Dinesh Thumma, 2 weeks ago

Owner: set to Dinesh Thumma
Status: newassigned
Note: See TracTickets for help on using tickets.
Back to Top