Ticket #3050: values.diff

File values.diff, 3.2 KB (added by Honza Král <Honza.Kral@…>, 9 years ago)

patch implementing the feature

  • django/db/models/query.py

     
    510510
    511511class ValuesQuerySet(QuerySet):
    512512    def iterator(self):
    513         # select_related and select aren't supported in values().
     513        # select_related isn't supported in values().
    514514        self._select_related = False
    515         self._select = {}
    516515
    517516        # self._fields is a list of field names to fetch.
    518517        if self._fields:
    519             columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
     518            if not self._select:
     519                columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
     520            else:
     521                columns = []
     522                for f in self._fields:
     523                    if f in [field.name for field in self.model._meta.fields]:
     524                        columns.append( self.model._meta.get_field(f, many_to_many=False).column )
     525                    elif not self._select.has_key( f ):
     526                        raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f )
     527
     528
    520529            field_names = self._fields
    521530        else: # Default to all fields.
    522531            columns = [f.column for f in self.model._meta.fields]
     
    525534        cursor = connection.cursor()
    526535        select, sql, params = self._get_sql_clause()
    527536        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
     537
     538        # Add any additional SELECTs.
     539        if self._select:
     540            select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
     541       
    528542        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
    529543        while 1:
    530544            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
  • tests/modeltests/lookup/models.py

     
    106106[('headline', 'Article 7'), ('id', 7)]
    107107[('headline', 'Article 1'), ('id', 1)]
    108108
     109# you can use values() even on extra fields
     110>>> for d in Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_one'):
     111...     i = d.items()
     112...     i.sort()
     113...     i
     114[('id', 5), ('id_plus_one', 6)]
     115[('id', 6), ('id_plus_one', 7)]
     116[('id', 4), ('id_plus_one', 5)]
     117[('id', 2), ('id_plus_one', 3)]
     118[('id', 3), ('id_plus_one', 4)]
     119[('id', 7), ('id_plus_one', 8)]
     120[('id', 1), ('id_plus_one', 2)]
     121
     122# however, an exception FieldDoesNotExist will still be thrown
     123# if you try to access non-existent field (field that is neither in model nor extra)
     124>>> Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_two')
     125Traceback (most recent call last):
     126    ...
     127FieldDoesNotExist: Article has no field named 'id_plus_two'
     128
    109129# You can use values() with iterator() for memory savings, because iterator()
    110130# uses database-level iteration.
    111131>>> for d in Article.objects.values('id', 'headline').iterator():
Back to Top