From 12e5b87b89074cd0380ddcdadd24a6c621178c07 Mon Sep 17 00:00:00 2001 From: Andy Chosak Date: Wed, 8 Oct 2014 15:12:42 -0400 Subject: [PATCH] [1.7.x] Fixed #23420 - broken warning for unbound naive datetime objects Fixed issue with warning message displayed for unbound naive datetime objects when USE_TZ is True. Adds unit test that demonstrates the issue (discoverable when using a custom lookup in MySQL). Backport of ceb1ffcc8d from master. Conflicts: tests/custom_lookups/tests.py --- django/db/models/fields/__init__.py | 8 +++++-- docs/releases/1.7.2.txt | 3 +++ tests/custom_lookups/models.py | 8 +++++++ tests/custom_lookups/tests.py | 34 ++++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 0db51ca60d4..a734b21676a 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1272,9 +1272,13 @@ class DateTimeField(DateField): # For backwards compatibility, interpret naive datetimes in local # time. This won't work during DST change, but we can't do much # about it, so we let the exceptions percolate up the call stack. - warnings.warn("DateTimeField %s.%s received a naive datetime (%s)" + try: + name = '%s.%s' % (self.model.__name__, self.name) + except AttributeError: + name = '(unbound)' + warnings.warn("DateTimeField %s received a naive datetime (%s)" " while time zone support is active." % - (self.model.__name__, self.name, value), + (name, value), RuntimeWarning) default_timezone = timezone.get_default_timezone() value = timezone.make_aware(value, default_timezone) diff --git a/docs/releases/1.7.2.txt b/docs/releases/1.7.2.txt index 7b455db62ec..e50875305a0 100644 --- a/docs/releases/1.7.2.txt +++ b/docs/releases/1.7.2.txt @@ -43,3 +43,6 @@ Bugfixes * Fixed a migrations crash when adding ``GeometryField``\s with ``blank=True`` on PostGIS (:ticket:`23731`). + +* Allowed usage of ``DateTimeField()`` as ``Transform.output_field`` + (:ticket:`23420`). diff --git a/tests/custom_lookups/models.py b/tests/custom_lookups/models.py index 9841b36ce56..82a835e1607 100644 --- a/tests/custom_lookups/models.py +++ b/tests/custom_lookups/models.py @@ -11,3 +11,11 @@ class Author(models.Model): def __str__(self): return self.name + + +@python_2_unicode_compatible +class MySQLUnixTimestamp(models.Model): + timestamp = models.PositiveIntegerField() + + def __str__(self): + return self.name diff --git a/tests/custom_lookups/tests.py b/tests/custom_lookups/tests.py index c89b268f6e1..c3df3e8cd4e 100644 --- a/tests/custom_lookups/tests.py +++ b/tests/custom_lookups/tests.py @@ -1,13 +1,14 @@ from __future__ import unicode_literals -from datetime import date +from datetime import date, datetime +import time import unittest from django.core.exceptions import FieldError from django.db import models from django.db import connection -from django.test import TestCase -from .models import Author +from django.test import TestCase, override_settings +from .models import Author, MySQLUnixTimestamp class Div3Lookup(models.Lookup): @@ -150,6 +151,18 @@ class InMonth(models.lookups.Lookup): (lhs, rhs, lhs, rhs), params) +class DateTimeTransform(models.Transform): + lookup_name = 'as_datetime' + + @property + def output_field(self): + return models.DateTimeField() + + def as_sql(self, qn, connection): + lhs, params = qn.compile(self.lhs) + return 'from_unixtime({})'.format(lhs), params + + class LookupTests(TestCase): def test_basic_lookup(self): a1 = Author.objects.create(name='a1', age=1) @@ -229,6 +242,21 @@ class LookupTests(TestCase): models.IntegerField._unregister_lookup(Div3Transform) +@override_settings(USE_TZ=True) +class DateTimeLookupTests(TestCase): + @unittest.skipUnless(connection.vendor == 'mysql', "MySQL specific SQL used") + def test_datetime_output_field(self): + models.PositiveIntegerField.register_lookup(DateTimeTransform) + try: + ut = MySQLUnixTimestamp.objects.create(timestamp=time.time()) + y2k = datetime(2000, 1, 1) + self.assertQuerysetEqual( + MySQLUnixTimestamp.objects.filter(timestamp__as_datetime__gt=y2k), + [ut], lambda x: x) + finally: + models.PositiveIntegerField._unregister_lookup(DateTimeTransform) + + class YearLteTests(TestCase): def setUp(self): models.DateField.register_lookup(YearTransform)