Ticket #2939: distinct-values-count.patch

File distinct-values-count.patch, 2.8 KB (added by SmileyChris, 8 years ago)
  • django/db/models/query.py

     
    235235
    236236        cursor = connection.cursor()
    237237        if self._distinct:
    238             id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
    239                     backend.quote_name(self.model._meta.pk.column))
    240             cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params)
     238            columns = ', '.join(self._get_distinct_columns())
     239            cursor.execute("SELECT COUNT(DISTINCT(%s))" % columns + sql, params)
    241240        else:
    242241            cursor.execute("SELECT COUNT(*)" + sql, params)
    243242        count = cursor.fetchone()[0]
     
    251250
    252251        return count
    253252
     253    def _get_distinct_columns(self):
     254        "Returns distinct columns, used for count()"
     255        return ["%s.%s" % (backend.quote_name(self.model._meta.db_table),
     256                           backend.quote_name(self.model._meta.pk.column))]
     257
    254258    def get(self, *args, **kwargs):
    255259        "Performs the SELECT and returns a single object matching the given keyword arguments."
    256260        clone = self.filter(*args, **kwargs)
     
    573577        # select_related isn't supported in values().
    574578        self._select_related = False
    575579
     580    def _get_distinct_columns(self):
     581        "Returns distinct columns, used for count()"
     582        if not self._fields:
     583            return super(ValuesQuerySet, self)._get_distinct_columns()
     584        columns = [self.model._meta.get_field(f, many_to_many=False).column
     585                   for f in self._fields]
     586        return ['%s.%s' % (backend.quote_name(self.model._meta.db_table),
     587                           backend.quote_name(c)) for c in columns]
     588
    576589    def iterator(self):
    577590        try:
    578591            select, sql, params = self._get_sql_clause()
  • tests/modeltests/lookup/models.py

     
    165165>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
    166166True
    167167
     168# .values(*fields).distinct().count() will return the correct number of
     169# distinct records.
     170>>> Article.objects.values('pub_date').count()
     1717
     172>>> len(Article.objects.values('pub_date').distinct())
     1735
     174>>> Article.objects.values('pub_date').distinct().count()
     1755
     176
     177# And make sure it still works if no fields are passed:
     178>>> len(Article.objects.values().distinct())
     1797
     180>>> Article.objects.values().distinct().count()
     1817
     182
    168183# Every DateField and DateTimeField creates get_next_by_FOO() and
    169184# get_previous_by_FOO() methods.
    170185# In the case of identical date values, these methods will use the ID as a
Back to Top