Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #19360 -- Raised an explicit exception for aggregates on date/t…

…ime fields in sqlite3

Thanks lsaffre for the report and Chris Medrela for the initial
patch.
  • Loading branch information...
commit eb6c107624930c97390185fdbf7f887c50665808 1 parent 2e55cf5
Nick Sandford authored January 11, 2013 claudep committed January 11, 2013
13  django/db/backends/sqlite3/base.py
@@ -18,6 +18,8 @@
18 18
 from django.db.backends.sqlite3.client import DatabaseClient
19 19
 from django.db.backends.sqlite3.creation import DatabaseCreation
20 20
 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
  21
+from django.db.models import fields
  22
+from django.db.models.sql import aggregates
21 23
 from django.utils.dateparse import parse_date, parse_datetime, parse_time
22 24
 from django.utils.functional import cached_property
23 25
 from django.utils.safestring import SafeBytes
@@ -127,6 +129,17 @@ def bulk_batch_size(self, fields, objs):
127 129
         limit = 999 if len(fields) > 1 else 500
128 130
         return (limit // len(fields)) if len(fields) > 0 else len(objs)
129 131
 
  132
+    def check_aggregate_support(self, aggregate):
  133
+        bad_fields = (fields.DateField, fields.DateTimeField, fields.TimeField)
  134
+        bad_aggregates = (aggregates.Sum, aggregates.Avg,
  135
+                          aggregates.Variance, aggregates.StdDev)
  136
+        if (isinstance(aggregate.source, bad_fields) and
  137
+                isinstance(aggregate, bad_aggregates)):
  138
+            raise NotImplementedError(
  139
+                'You cannot use Sum, Avg, StdDev and Variance aggregations '
  140
+                'on date/time fields in sqlite3 '
  141
+                'since date/time is saved as text.')
  142
+
130 143
     def date_extract_sql(self, lookup_type, field_name):
131 144
         # sqlite doesn't support extract, so we fake it with the user-defined
132 145
         # function django_extract that's registered in connect(). Note that
8  docs/ref/models/querysets.txt
@@ -2188,6 +2188,14 @@ Django provides the following aggregation functions in the
2188 2188
 aggregate functions, see
2189 2189
 :doc:`the topic guide on aggregation </topics/db/aggregation>`.
2190 2190
 
  2191
+.. warning::
  2192
+
  2193
+    SQLite can't handle aggregation on date/time fields out of the box.
  2194
+    This is because there are no native date/time fields in SQLite and Django
  2195
+    currently emulates these features using a text field. Attempts to use
  2196
+    aggregation on date/time fields in SQLite will raise
  2197
+    ``NotImplementedError``.
  2198
+
2191 2199
 Avg
2192 2200
 ~~~
2193 2201
 
11  tests/regressiontests/backends/models.py
@@ -75,3 +75,14 @@ class Article(models.Model):
75 75
 
76 76
     def __str__(self):
77 77
         return self.headline
  78
+
  79
+
  80
+@python_2_unicode_compatible
  81
+class Item(models.Model):
  82
+    name = models.CharField(max_length=30)
  83
+    date = models.DateField()
  84
+    time = models.TimeField()
  85
+    last_modified = models.DateTimeField()
  86
+
  87
+    def __str__(self):
  88
+        return self.name
18  tests/regressiontests/backends/tests.py
@@ -12,6 +12,7 @@
12 12
     IntegrityError, transaction)
13 13
 from django.db.backends.signals import connection_created
14 14
 from django.db.backends.postgresql_psycopg2 import version as pg_version
  15
+from django.db.models import fields, Sum, Avg, Variance, StdDev
15 16
 from django.db.utils import ConnectionHandler, DatabaseError, load_backend
16 17
 from django.test import (TestCase, skipUnlessDBFeature, skipIfDBFeature,
17 18
     TransactionTestCase)
@@ -362,6 +363,22 @@ def test_parameter_escaping(self):
362 363
         self.assertTrue(int(response))
363 364
 
364 365
 
  366
+class SqlliteAggregationTests(TestCase):
  367
+    """
  368
+    #19360: Raise NotImplementedError when aggregating on date/time fields.
  369
+    """
  370
+    @unittest.skipUnless(connection.vendor == 'sqlite',
  371
+                         "No need to check SQLite aggregation semantics")
  372
+    def test_aggregation(self):
  373
+        for aggregate in (Sum, Avg, Variance, StdDev):
  374
+            self.assertRaises(NotImplementedError,
  375
+                models.Item.objects.all().aggregate, aggregate('time'))
  376
+            self.assertRaises(NotImplementedError,
  377
+                models.Item.objects.all().aggregate, aggregate('date'))
  378
+            self.assertRaises(NotImplementedError,
  379
+                models.Item.objects.all().aggregate, aggregate('last_modified'))
  380
+
  381
+
365 382
 class BackendTestCase(TestCase):
366 383
 
367 384
     def create_squares_with_executemany(self, args):
@@ -400,7 +417,6 @@ def test_cursor_executemany_with_iterator(self):
400 417
             self.create_squares_with_executemany(args)
401 418
         self.assertEqual(models.Square.objects.count(), 9)
402 419
 
403  
-
404 420
     def test_unicode_fetches(self):
405 421
         #6254: fetchone, fetchmany, fetchall return strings as unicode objects
406 422
         qn = connection.ops.quote_name

0 notes on commit eb6c107

Please sign in to comment.
Something went wrong with that request. Please try again.