﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
14601	ValuesQuerySet join types not being promoted	ryanbutterfield	nobody	"In the following test case the join type of the User model isn't promoted (to a LEFT OUTER JOIN) as it should be when using a !ValuesQuerySet. This results in nothing being returned when the Item.person !ForeignKey is null.

{{{
#!python
class User(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    
class Person(models.Model):
    user = models.ForeignKey(User)

class Item(models.Model):
    person = models.ForeignKey(Person, null=True)
    amount = models.IntegerField()
}}}

To replicate the following is required:

1. Three (or more) models deep linked by !ForeignKey's.[[BR]]
2. The first model's (Item) !ForeignKey should allow null values.[[BR]]
3. The query should reference the second model (Person), but not the third (User), before conversion to a !ValuesQuerySet.[[BR]]
4. The values list (that is passed to !ValueQuerySet) should reference a field in the third model (User).[[BR]]

The following snippet shows what happens currently. Note that the Q objects aren't required, they are just for satisfying point 3 above.

{{{
#!python
>>> Item.objects.create(person=None, amount=123)
<Item: Item object>

>>> Item.objects.values('amount', 'person__user__first_name', 'person__user__last_name')
[{'amount': 123, 'person__user__last_name': None, 'person__user__first_name': None}]

>>> Item.objects.filter(Q(person__isnull=True) | Q(person__isnull=False))
[<Item: Item object>]

>>> Item.objects.filter(Q(person__isnull=True) | Q(person__isnull=False)).values('amount', 'person__user__first_name', 'person__user__last_name')
[]
}}}

What happens:

- When the filter is constructed, a query.alias_map entry is created for the Person model. It is NULLABLE so the join type is set to LOUTER which is correct.[[BR]]
- During the conversion to a !ValuesQuerySet, promote_alias_chain is called on the fields from the User model (eg. person!__user!__first_name or person!__user!__last_name).[[BR]]
- Because Person had been previously promoted promote_alias returns False which causes promote_alias_chain to not promote the User model.[[BR]]

What should happen:

- promote_alias should return True if it promotes the join or if the join has previously been promoted, so that promote_alias_chain can promote the remainder of the chain correctly.

The included diff provides a simple fix to promote_alias and a test case that tests the fix."	Bug	closed	Database layer (models, ORM)	dev	Normal	fixed	ValuesQuerySet promote_alias		Accepted	1	0	0	1	0	0
