summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2015-10-13 20:25:06 +0200
committerTim Graham <timograham@gmail.com>2015-10-21 19:24:19 -0400
commit0f6d51e6a0a22e37e45c4bf452ddb49723e2f956 (patch)
treea4076fd02e1fcbbf3774b01e669dc1c8ef741256
parent0dbe897ab5ea055ed53a219f642348d98e1c3cf9 (diff)
Fixed #25470 -- Avoided unnecessary, expensive DATETIME typecast on MySQL.
-rw-r--r--django/db/backends/mysql/operations.py18
-rw-r--r--tests/dates/models.py2
-rw-r--r--tests/dates/tests.py34
3 files changed, 42 insertions, 12 deletions
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py
index 85854dc1b6..8fc67ff8e3 100644
--- a/django/db/backends/mysql/operations.py
+++ b/django/db/backends/mysql/operations.py
@@ -27,17 +27,15 @@ class DatabaseOperations(BaseDatabaseOperations):
return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
def date_trunc_sql(self, lookup_type, field_name):
- fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
- format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
- format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
- try:
- i = fields.index(lookup_type) + 1
- except ValueError:
- sql = field_name
+ fields = {
+ 'year': '%%Y-01-01',
+ 'month': '%%Y-%%m-01',
+ } # Use double percents to escape.
+ if lookup_type in fields:
+ format_str = fields[lookup_type]
+ return "CAST(DATE_FORMAT(%s, '%s') AS DATE)" % (field_name, format_str)
else:
- format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
- sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
- return sql
+ return "DATE(%s)" % (field_name)
def _convert_field_to_tz(self, field_name, tzname):
if settings.USE_TZ:
diff --git a/tests/dates/models.py b/tests/dates/models.py
index 58e6d10d91..2161b2b356 100644
--- a/tests/dates/models.py
+++ b/tests/dates/models.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
from django.db import models
+from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
@@ -8,6 +9,7 @@ from django.utils.encoding import python_2_unicode_compatible
class Article(models.Model):
title = models.CharField(max_length=100)
pub_date = models.DateField()
+ pub_datetime = models.DateTimeField(default=timezone.now())
categories = models.ManyToManyField("Category", related_name="articles")
diff --git a/tests/dates/tests.py b/tests/dates/tests.py
index c0f399b091..3b6fb5505b 100644
--- a/tests/dates/tests.py
+++ b/tests/dates/tests.py
@@ -1,9 +1,11 @@
from __future__ import unicode_literals
import datetime
+from unittest import skipUnless
from django.core.exceptions import FieldError
-from django.test import TestCase
+from django.db import connection
+from django.test import TestCase, override_settings
from django.utils import six
from .models import Article, Category, Comment
@@ -95,7 +97,7 @@ class DatesTests(TestCase):
self,
FieldError,
"Cannot resolve keyword u?'invalid_field' into field. Choices are: "
- "categories, comments, id, pub_date, title",
+ "categories, comments, id, pub_date, pub_datetime, title",
Article.objects.dates,
"invalid_field",
"year",
@@ -121,3 +123,31 @@ class DatesTests(TestCase):
"year",
order="bad order",
)
+
+ @override_settings(USE_TZ=False)
+ def test_dates_trunc_datetime_fields(self):
+ Article.objects.bulk_create(
+ Article(pub_date=pub_datetime.date(), pub_datetime=pub_datetime)
+ for pub_datetime in [
+ datetime.datetime(2015, 10, 21, 18, 1),
+ datetime.datetime(2015, 10, 21, 18, 2),
+ datetime.datetime(2015, 10, 22, 18, 1),
+ datetime.datetime(2015, 10, 22, 18, 2),
+ ]
+ )
+ self.assertQuerysetEqual(
+ Article.objects.dates('pub_datetime', 'day', order='ASC'), [
+ "datetime.date(2015, 10, 21)",
+ "datetime.date(2015, 10, 22)",
+ ]
+ )
+
+ @skipUnless(connection.vendor == 'mysql', "Test checks MySQL query syntax")
+ def test_dates_avoid_datetime_cast(self):
+ Article.objects.create(pub_date=datetime.date(2015, 10, 21))
+ for kind in ['day', 'month', 'year']:
+ qs = Article.objects.dates('pub_date', kind)
+ if kind == 'day':
+ self.assertIn('DATE(', str(qs.query))
+ else:
+ self.assertIn(' AS DATE)', str(qs.query))