Code

Ticket #2482: values-flat.diff

File values-flat.diff, 3.1 KB (added by mccutchen@…, 8 years ago)

Diff against trunk revision 3522

Line 
1Index: django/db/models/query.py
2===================================================================
3--- django/db/models/query.py   (revision 3522)
4+++ django/db/models/query.py   (working copy)
5@@ -305,8 +305,19 @@
6     # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
7     ##################################################
8
9-    def values(self, *fields):
10-        return self._clone(klass=ValuesQuerySet, _fields=fields)
11+    def values(self, *fields, **kwds):
12+        """
13+        Returns a list of dictionaries instead of object instances.  Only
14+        retrieves fields listed in '*fields'.  If the keyword argument 'flat'
15+        is True, returns a "flattened" list of field values.
16+        """
17+        if kwds:
18+            assert 'flat' in kwds, "only accepts keyword argument 'flat'"
19+            assert kwds['flat'] in (True, False), "keyword argument 'flat' must be either True or False"
20+            flat = kwds['flat']
21+        else:
22+            flat = False
23+        return self._clone(klass=ValuesQuerySet, _fields=fields, _flat=flat)
24
25     def dates(self, field_name, kind, order='ASC'):
26         """
27@@ -531,11 +542,21 @@
28             if not rows:
29                 raise StopIteration
30             for row in rows:
31-                yield dict(zip(field_names, row))
32+                # if self._flat is True, return a "flattened" list of
33+                # field values as a plain list or a list of tuples
34+                if self._flat:
35+                    if len(field_names) == 1:
36+                        yield row[0]
37+                    else:
38+                        yield tuple(row)
39+                # otherwise, return a dict of field names and values
40+                else:
41+                    yield dict(zip(field_names, row))
42
43     def _clone(self, klass=None, **kwargs):
44         c = super(ValuesQuerySet, self)._clone(klass, **kwargs)
45         c._fields = self._fields[:]
46+        c._flat = self._flat
47         return c
48
49 class DateQuerySet(QuerySet):
50Index: tests/modeltests/lookup/models.py
51===================================================================
52--- tests/modeltests/lookup/models.py   (revision 3522)
53+++ tests/modeltests/lookup/models.py   (working copy)
54@@ -124,6 +124,23 @@
55 >>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
56 True
57
58+# if you specify only one field and pass the keyword argument flat=True, a
59+# plain list of field values is returned
60+>>> list(Article.objects.order_by('id').values('id', flat=True)) == [1, 2, 3, 4, 5, 6, 7]
61+True
62+
63+# if you specify more than one field and pass the keyword argument flat=True,
64+# a list of tuples of field values is returned
65+>>> for t in Article.objects.order_by('id').values('id', 'headline', flat=True):
66+...     t
67+(1, 'Article 1')
68+(2, 'Article 2')
69+(3, 'Article 3')
70+(4, 'Article 4')
71+(5, 'Article 5')
72+(6, 'Article 6')
73+(7, 'Article 7')
74+
75 # Every DateField and DateTimeField creates get_next_by_FOO() and
76 # get_previous_by_FOO() methods.
77 # In the case of identical date values, these methods will use the ID as a