diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 1143bb95301..b9f320c0e0e 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1402,9 +1402,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 f673e78b72a..872427e8833 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): @@ -172,6 +173,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) @@ -353,6 +366,21 @@ class BilateralTransformTests(TestCase): models.IntegerField._unregister_lookup(Mult3BilateralTransform) +@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)