Commit 18344286 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
Browse files

Fixed a problem with values() and values_list() queries and nullable joins.

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: http://code.djangoproject.com/svn/django/trunk@7740 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent b8f7b39c
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -679,12 +679,16 @@ class Query(object):
        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 @@ class Query(object):
                        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
                self.select.append((final_alias, col))
                self.select_fields.append(field)
        except MultiJoin:
+8 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ class Item(models.Model):

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):
        return self.name
@@ -191,6 +191,8 @@ by 'info'. Helps detect some problems later.
>>> r1.save()
>>> r2 = Report(name='r2', creator=a3)
>>> r2.save()
>>> r3 = Report(name='r3')
>>> r3.save()

Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering
will be rank3, rank2, rank1.
@@ -713,5 +715,10 @@ in MySQL. This exercises that case.
>>> 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
appropriately.
>>> Report.objects.values_list("creator__extra__info", flat=True).order_by("name")
[u'e1', u'e2', None]

"""}