[1.0.X] Fixed #10256 -- Corrected the interaction of extra(select=) with values() and values_list() where an explicit list of columns is requested.
Merge of r9837 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9884 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8366ef412e
commit
c2807db683
|
@ -652,10 +652,11 @@ class ValuesQuerySet(QuerySet):
|
|||
# names of the model fields to select.
|
||||
|
||||
def iterator(self):
|
||||
if (not self.extra_names and
|
||||
len(self.field_names) != len(self.model._meta.fields)):
|
||||
# Purge any extra columns that haven't been explicitly asked for
|
||||
if self.extra_names is not None:
|
||||
self.query.trim_extra_select(self.extra_names)
|
||||
names = self.query.extra_select.keys() + self.field_names
|
||||
|
||||
for row in self.query.results_iter():
|
||||
yield dict(zip(names, row))
|
||||
|
||||
|
@ -668,24 +669,25 @@ class ValuesQuerySet(QuerySet):
|
|||
instance.
|
||||
"""
|
||||
self.query.clear_select_fields()
|
||||
self.extra_names = []
|
||||
|
||||
if self._fields:
|
||||
self.extra_names = []
|
||||
if not self.query.extra_select:
|
||||
field_names = list(self._fields)
|
||||
self.field_names = list(self._fields)
|
||||
else:
|
||||
field_names = []
|
||||
self.query.default_cols = False
|
||||
self.field_names = []
|
||||
for f in self._fields:
|
||||
if self.query.extra_select.has_key(f):
|
||||
self.extra_names.append(f)
|
||||
else:
|
||||
field_names.append(f)
|
||||
self.field_names.append(f)
|
||||
else:
|
||||
# Default to all fields.
|
||||
field_names = [f.attname for f in self.model._meta.fields]
|
||||
self.extra_names = None
|
||||
self.field_names = [f.attname for f in self.model._meta.fields]
|
||||
|
||||
self.query.add_fields(field_names, False)
|
||||
self.query.default_cols = False
|
||||
self.field_names = field_names
|
||||
self.query.add_fields(self.field_names, False)
|
||||
|
||||
def _clone(self, klass=None, setup=False, **kwargs):
|
||||
"""
|
||||
|
@ -712,7 +714,8 @@ class ValuesQuerySet(QuerySet):
|
|||
|
||||
class ValuesListQuerySet(ValuesQuerySet):
|
||||
def iterator(self):
|
||||
self.query.trim_extra_select(self.extra_names)
|
||||
if self.extra_names is not None:
|
||||
self.query.trim_extra_select(self.extra_names)
|
||||
if self.flat and len(self._fields) == 1:
|
||||
for row in self.query.results_iter():
|
||||
yield row[0]
|
||||
|
@ -720,13 +723,21 @@ class ValuesListQuerySet(ValuesQuerySet):
|
|||
for row in self.query.results_iter():
|
||||
yield tuple(row)
|
||||
else:
|
||||
# When extra(select=...) is involved, the extra cols come are
|
||||
# always at the start of the row, so we need to reorder the fields
|
||||
# When extra(select=...) is involved, the extra cols are
|
||||
# always at the start of the row, and we need to reorder the fields
|
||||
# to match the order in self._fields.
|
||||
names = self.query.extra_select.keys() + self.field_names
|
||||
|
||||
# If a field list has been specified, use it. Otherwise, use the
|
||||
# full list of fields, including extras.
|
||||
if self._fields:
|
||||
fields = self._fields
|
||||
else:
|
||||
fields = names
|
||||
|
||||
for row in self.query.results_iter():
|
||||
data = dict(zip(names, row))
|
||||
yield tuple([data[f] for f in self._fields])
|
||||
yield tuple([data[f] for f in fields])
|
||||
|
||||
def _clone(self, *args, **kwargs):
|
||||
clone = super(ValuesListQuerySet, self)._clone(*args, **kwargs)
|
||||
|
|
|
@ -30,6 +30,11 @@ class Order(models.Model):
|
|||
created_by = models.ForeignKey(User)
|
||||
text = models.TextField()
|
||||
|
||||
class TestObject(models.Model):
|
||||
first = models.CharField(max_length=20)
|
||||
second = models.CharField(max_length=20)
|
||||
third = models.CharField(max_length=20)
|
||||
|
||||
__test__ = {"API_TESTS": """
|
||||
# Regression tests for #7314 and #7372
|
||||
|
||||
|
@ -115,4 +120,75 @@ True
|
|||
# cause incorrect SQL to be produced otherwise.
|
||||
>>> RevisionableModel.objects.extra(select={"the_answer": 'id'}).dates('when', 'month')
|
||||
[datetime.datetime(2008, 9, 1, 0, 0)]
|
||||
|
||||
# Regression test for #10256... If there is a values() clause, Extra columns are
|
||||
# only returned if they are explicitly mentioned.
|
||||
>>> TestObject(first='first', second='second', third='third').save()
|
||||
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values()
|
||||
[{'bar': u'second', 'third': u'third', 'second': u'second', 'whiz': u'third', 'foo': u'first', 'id': 1, 'first': u'first'}]
|
||||
|
||||
# Extra clauses after an empty values clause are still included
|
||||
>>> TestObject.objects.values().extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third'))))
|
||||
[{'bar': u'second', 'third': u'third', 'second': u'second', 'whiz': u'third', 'foo': u'first', 'id': 1, 'first': u'first'}]
|
||||
|
||||
# Extra columns are ignored if not mentioned in the values() clause
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values('first', 'second')
|
||||
[{'second': u'second', 'first': u'first'}]
|
||||
|
||||
# Extra columns after a non-empty values() clause are ignored
|
||||
>>> TestObject.objects.values('first', 'second').extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third'))))
|
||||
[{'second': u'second', 'first': u'first'}]
|
||||
|
||||
# Extra columns can be partially returned
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values('first', 'second', 'foo')
|
||||
[{'second': u'second', 'foo': u'first', 'first': u'first'}]
|
||||
|
||||
# Also works if only extra columns are included
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values('foo', 'whiz')
|
||||
[{'foo': u'first', 'whiz': u'third'}]
|
||||
|
||||
# Values list works the same way
|
||||
# All columns are returned for an empty values_list()
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list()
|
||||
[(u'first', u'second', u'third', 1, u'first', u'second', u'third')]
|
||||
|
||||
# Extra columns after an empty values_list() are still included
|
||||
>>> TestObject.objects.values_list().extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third'))))
|
||||
[(u'first', u'second', u'third', 1, u'first', u'second', u'third')]
|
||||
|
||||
# Extra columns ignored completely if not mentioned in values_list()
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('first', 'second')
|
||||
[(u'first', u'second')]
|
||||
|
||||
# Extra columns after a non-empty values_list() clause are ignored completely
|
||||
>>> TestObject.objects.values_list('first', 'second').extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third'))))
|
||||
[(u'first', u'second')]
|
||||
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('second', flat=True)
|
||||
[u'second']
|
||||
|
||||
# Only the extra columns specified in the values_list() are returned
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('first', 'second', 'whiz')
|
||||
[(u'first', u'second', u'third')]
|
||||
|
||||
# ...also works if only extra columns are included
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('foo','whiz')
|
||||
[(u'first', u'third')]
|
||||
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('whiz', flat=True)
|
||||
[u'third']
|
||||
|
||||
# ... and values are returned in the order they are specified
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('whiz','foo')
|
||||
[(u'third', u'first')]
|
||||
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('first','id')
|
||||
[(u'first', 1)]
|
||||
|
||||
>>> TestObject.objects.extra(select=SortedDict((('foo','first'),('bar','second'),('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')
|
||||
[(u'third', u'first', u'second', 1)]
|
||||
|
||||
"""}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue