Django

Code

Ticket #2482: valuelist.diff

File valuelist.diff, 4.0 kB (added by mccutchen@gmail.com, 2 years ago)

Patch which implements valuelist() method

  • django/db/models/query.py

    old new  
    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

    old new  
    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