From ceb1ffcc8da92a82338582bc6801de4bc8f05e32 Mon Sep 17 00:00:00 2001
From: Andy Chosak <chosak@gmail.com>
Date: Wed, 8 Oct 2014 15:12:42 -0400
Subject: [PATCH] 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).
---
 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 1143bb9530..b9f320c0e0 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 7b455db62e..e50875305a 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 9841b36ce5..82a835e160 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 f673e78b72..872427e883 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)