Ticket #2482: valuelist.diff

File valuelist.diff, 4.0 KB (added by mccutchen@…, 9 years ago)

Patch which implements valuelist() method

  • django/db/models/query.py

     
    308308    def values(self, *fields):
    309309        return self._clone(klass=ValuesQuerySet, _fields=fields)
    310310
     311    def valuelist(self, *fields):
     312        return self._clone(klass=ValueListQuerySet, _fields=fields)
     313
    311314    def dates(self, field_name, kind, order='ASC'):
    312315        """
    313316        Returns a list of datetime objects representing all available dates
     
    509512        return select, " ".join(sql), params
    510513
    511514class ValuesQuerySet(QuerySet):
    512     def iterator(self):
     515    def get_columns(self):
     516        if self._fields:
     517            return [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
     518        else:
     519            return [f.column for f in self.model._meta.fields]
     520
     521    def get_field_names(self):
     522        return self._fields and self._fields or [f.attname for f in self.model._meta.fields]
     523
     524    def get_values_cursor(self):
    513525        # select_related and select aren't supported in values().
    514526        self._select_related = False
    515527        self._select = {}
    516528
    517         # self._fields is a list of field names to fetch.
    518         if self._fields:
    519             columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
    520             field_names = self._fields
    521         else: # Default to all fields.
    522             columns = [f.column for f in self.model._meta.fields]
    523             field_names = [f.attname for f in self.model._meta.fields]
    524 
     529        columns = self.get_columns()
    525530        cursor = connection.cursor()
    526531        select, sql, params = self._get_sql_clause()
    527532        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
    528533        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     534        return cursor
     535
     536    def iterator(self):
     537        cursor = self.get_values_cursor()
     538        field_names = self.get_field_names()
    529539        while 1:
    530540            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
    531541            if not rows:
     
    538548        c._fields = self._fields[:]
    539549        return c
    540550
     551class ValueListQuerySet(ValuesQuerySet):
     552    def iterator(self):
     553        cursor = self.get_values_cursor()
     554        while 1:
     555            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
     556            if not rows:
     557                raise StopIteration
     558            for row in rows:
     559                if len(row) == 1:
     560                    yield row[0]
     561                else:
     562                    yield tuple(row)
     563
     564    def _clone(self, klass=None, **kwargs):
     565        c = super(ValueListQuerySet, self)._clone(klass, **kwargs)
     566        c._fields = self._fields[:]
     567        return c
     568
    541569class DateQuerySet(QuerySet):
    542570    def iterator(self):
    543571        from django.db.backends.util import typecast_timestamp
  • tests/modeltests/lookup/models.py

     
    124124>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
    125125True
    126126
     127# valuelist() returns a list of object field values instead of object instances.  Like
     128# values(), you can specify the fields whose values you want to retrieve.
     129>>> list(Article.objects.order_by('id').valuelist('id')) == [1, 2, 3, 4, 5, 6, 7]
     130True
     131
     132# if you specify more than one field, a list of tuples of field values is returned
     133>>> for t in Article.objects.order_by('id').valuelist('id', 'headline'):
     134...     t
     135(1, 'Article 1')
     136(2, 'Article 2')
     137(3, 'Article 3')
     138(4, 'Article 4')
     139(5, 'Article 5')
     140(6, 'Article 6')
     141(7, 'Article 7')
     142
    127143# Every DateField and DateTimeField creates get_next_by_FOO() and
    128144# get_previous_by_FOO() methods.
    129145# In the case of identical date values, these methods will use the ID as a
Back to Top