#36945: .values() and .order_by() miss FilteredRelation when resolving aliases
shadowing relationship traversals
-------------------------------------+-------------------------------------
Reporter: Jacob | Owner: Sarah Boyce
Walls |
Type: Bug | Status: assigned
Component: Database | Version: 6.0
layer (models, ORM) | Keywords: FilteredRelation,
Severity: Normal | alias
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Here is a [
https://dryorm.xterm.info/filtered-relation-values-shadowing
fiddle] on DryORM demonstrating that when `.values()`/`.values_list()`
resolve aliases, they appropriately give priority to most aliases supplied
by `.annotate()`/`.alias()` before trying to parse `__` as relationship
traversals, but fail to account for annotations consisting of
`FilteredRelation`, which are stored in a different internal data
structure and therefore missed.
This leads to resolving an alias that happens to contain `__` as a
relationship traversal instead of the alias that was requested.
Here is the reproducer:
{{{#!py
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="Prince", ct=person_ct)
alias = "ct__model"
# This does not resolve to ContentType.model. Returns
Person.creator_id
qs = Person.objects.annotate(**{alias:
models.F("creator")}).values(alias)
print(qs)
# This does resolve to ContentType.model. Returns Person.ct.model
qs = Person.objects.annotate(
**{alias: models.FilteredRelation("creator",
condition=models.Q(creator__isnull=False))}
).values(alias)
print(qs)
}}}
Output:
{{{
<QuerySet [{'ct__model': 1}]>
<QuerySet [{'ct__model': 'person'}]>
}}}
In this example, since `alias` is a variable, and could be user-controlled
in the case of user-configurable reports, it is unexpected that for some
values of `alias`, the column it maps to might vary.
----
`.order_by()` is affected in the same way.
----
While this is not regarded as a security vulnerability, we thank
sw0rdl1ght for bringing the `.order_by()` case to the attention of the
security team.
--
Ticket URL: <
https://code.djangoproject.com/ticket/36945>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.