From 470ddafe9792fc58502993a16d9a0d3d2ed044d9 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Wed, 19 Dec 2007 12:23:59 +0000 Subject: [PATCH] queryset-refactor: Made qs.dates(...).count() work. This involved a slight change in the SQL for .dates() which appears to be correct and passes all the tests, but may have some side-effect I don't know about. Refs #6203. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6959 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/sql/datastructures.py | 4 +++- django/db/models/sql/query.py | 16 +++++++++------ tests/regressiontests/queries/models.py | 27 ++++++++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/django/db/models/sql/datastructures.py b/django/db/models/sql/datastructures.py index af3db23e02..59343aa515 100644 --- a/django/db/models/sql/datastructures.py +++ b/django/db/models/sql/datastructures.py @@ -50,12 +50,14 @@ class Count(Aggregate): quote_func = lambda x: x if isinstance(self.col, (list, tuple)): col = ('%s.%s' % tuple([quote_func(c) for c in self.col])) + elif hasattr(self.col, 'as_sql'): + col = self.col.as_sql(quote_func) else: col = self.col if self.distinct: return 'COUNT(DISTINCT %s)' % col else: - return 'COUNT(%s)' % self.col + return 'COUNT(%s)' % col class Date(object): """ diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index d9a558e522..2a5ee616d8 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -193,6 +193,8 @@ class Query(object): if obj.distinct and len(obj.select) > 1: obj = self.clone(CountQuery, _query=obj, where=WhereNode(), distinct=False) + obj.select = [] + obj.extra_select = SortedDict() obj.add_count_column() data = obj.execute_sql(SINGLE) if not data: @@ -1008,13 +1010,18 @@ class Query(object): def add_count_column(self): """ - Converts the query to do count(*) or count(distinct(pk)) in order to + Converts the query to do count(...) or count(distinct(pk)) in order to get its size. """ # TODO: When group_by support is added, this needs to be adjusted so # that it doesn't totally overwrite the select list. if not self.distinct: - select = Count() + if not self.select: + select = Count() + else: + assert len(self.select) == 1, \ + "Cannot add count col with multiple cols in 'select': %r" % self.select + select = Count(self.select[0]) else: opts = self.model._meta if not self.select: @@ -1229,11 +1236,8 @@ class DateQuery(Query): select = Date((alias, column), lookup_type, self.connection.ops.date_trunc_sql) self.select = [select] + self.distinct = True self.order_by = order == 'ASC' and [1] or [-1] - if self.connection.features.allows_group_by_ordinal: - self.group_by = [1] - else: - self.group_by = [select] class CountQuery(Query): """ diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 3c070a86ce..e7e78e23cd 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -2,6 +2,8 @@ Various complex queries that have been problematic in the past. """ +import datetime + from django.db import models from django.db.models.query import Q @@ -42,6 +44,7 @@ class Author(models.Model): class Item(models.Model): name = models.CharField(max_length=10) + created = models.DateTimeField() tags = models.ManyToManyField(Tag, blank=True, null=True) creator = models.ForeignKey(Author) note = models.ForeignKey(Note) @@ -129,15 +132,19 @@ by 'info'. Helps detect some problems later. >>> a4 = Author(name='a4', num=4004, extra=e2) >>> a4.save() ->>> i1 = Item(name='one', creator=a1, note=n3) +>>> time1 = datetime.datetime(2007, 12, 19, 22, 25, 0) +>>> time2 = datetime.datetime(2007, 12, 19, 21, 0, 0) +>>> time3 = datetime.datetime(2007, 12, 20, 22, 25, 0) +>>> time4 = datetime.datetime(2007, 12, 20, 21, 0, 0) +>>> i1 = Item(name='one', created=time1, creator=a1, note=n3) >>> i1.save() >>> i1.tags = [t1, t2] ->>> i2 = Item(name='two', creator=a2, note=n2) +>>> i2 = Item(name='two', created=time2, creator=a2, note=n2) >>> i2.save() >>> i2.tags = [t1, t3] ->>> i3 = Item(name='three', creator=a2, note=n3) +>>> i3 = Item(name='three', created=time3, creator=a2, note=n3) >>> i3.save() ->>> i4 = Item(name='four', creator=a4, note=n3) +>>> i4 = Item(name='four', created=time4, creator=a4, note=n3) >>> i4.save() >>> i4.tags = [t4] @@ -244,7 +251,7 @@ Bug #1878, #2939 # Create something with a duplicate 'name' so that we can test multi-column # cases (which require some tricky SQL transformations under the covers). ->>> xx = Item(name='four', creator=a2, note=n1) +>>> xx = Item(name='four', created=time1, creator=a2, note=n1) >>> xx.save() >>> Item.objects.exclude(name='two').values('creator', 'name').distinct().count() 4 @@ -471,5 +478,15 @@ Multiple filter statements are joined using "AND" all the time. [] >>> Author.objects.filter(Q(extra__note=n1)|Q(item__note=n3)).filter(id=a1.id) [] + +Bug #6203 +>>> Item.objects.count() +4 +>>> Item.objects.dates('created', 'month').count() +1 +>>> Item.objects.dates('created', 'day').count() +2 +>>> len(Item.objects.dates('created', 'day')) +2 """}