Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Browse files

Fixed a problem with values() and values_list() queries and nullable …


Previously, if we were querying across a nullable join and then a non-nullable
one, the second join would not be a LEFT OUTER join, which would exclude
certain valid results from the result set.

This is the same problem as [7597] but for values() field specifications, so
this covers the second case where Django adds extra stuff to the select-clause.

git-svn-id: bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 183442864837386df1f24d9cd0b39a3671ef3b04 1 parent b8f7b39
@malcolmt malcolmt authored
8 django/db/models/sql/
@@ -679,12 +679,16 @@ def promote_alias(self, alias, unconditional=False):
for the join to contain NULL values on the left. If 'unconditional' is
False, the join is only promoted if it is nullable, otherwise it is
always promoted.
+ Returns True if the join was promoted.
if ((unconditional or self.alias_map[alias][NULLABLE]) and
self.alias_map[alias] != self.LOUTER):
data = list(self.alias_map[alias])
data[JOIN_TYPE] = self.LOUTER
self.alias_map[alias] = tuple(data)
+ return True
+ return False
def change_aliases(self, change_map):
@@ -1294,10 +1298,12 @@ def add_fields(self, field_names, allow_m2m=True):
final_alias = join[LHS_ALIAS]
col = join[LHS_JOIN_COL]
joins = joins[:-1]
+ promote = False
for join in joins[1:]:
# Only nullable aliases are promoted, so we don't end up
# doing unnecessary left outer joins here.
- self.promote_alias(join)
+ if self.promote_alias(join, promote):
+ promote = True, col))
except MultiJoin:
9 tests/regressiontests/queries/
@@ -58,7 +58,7 @@ def __unicode__(self):
class Report(models.Model):
name = models.CharField(max_length=10)
- creator = models.ForeignKey(Author, to_field='num')
+ creator = models.ForeignKey(Author, to_field='num', null=True)
def __unicode__(self):
@@ -191,6 +191,8 @@ def __unicode__(self):
>>> r2 = Report(name='r2', creator=a3)
+>>> r3 = Report(name='r3')
Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering
will be rank3, rank2, rank1.
@@ -713,5 +715,10 @@ def __unicode__(self):
>>> mm = ManagedModel.objects.create(data='mm1', tag=t1, is_public=True)
>>> ManagedModel.objects.update(data='mm')
+A values() or values_list() query across joined models must use outer joins
+>>> Report.objects.values_list("creator__extra__info", flat=True).order_by("name")
+[u'e1', u'e2', None]
Please sign in to comment.
Something went wrong with that request. Please try again.