commit 8538fde6644a6ad8b4f2c8cb1aa9488c1da9e8c7
Author: Дилян Палаузов <dpa@mail.lab>
Date:   Thu Mar 1 20:53:56 2018 +0000

    Refs #28715 -  Prevent a migration changing DateTimeField(auto_now_add=True to default=timezone.now) from generating SQL
    
    ... likewise for DateField(auto_now_add=True) -> DateField(default=datetime.date.today)

diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index f1e8e66..df5e0e5 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -196,33 +196,34 @@ class BaseDatabaseSchemaEditor:
             'requires_literal_defaults must provide a prepare_default() method'
         )
 
-    def effective_default(self, field):
-        """Return a field's effective database default value."""
+    @staticmethod
+    def effective_default_before_callable(field):
+        """Return a field's effective database default callable or value"""
         if field.has_default():
-            default = field.get_default()
-        elif not field.null and field.blank and field.empty_strings_allowed:
-            if field.get_internal_type() == "BinaryField":
-                default = bytes()
-            else:
-                default = str()
-        elif getattr(field, 'auto_now', False) or getattr(field, 'auto_now_add', False):
+            return field._get_default
+        if not field.null and field.blank and field.empty_strings_allowed:
+            return bytes() if field.get_internal_type() == "BinaryField" else str()
+        if getattr(field, 'auto_now', False) or getattr(field, 'auto_now_add', False):
             default = datetime.now()
             internal_type = field.get_internal_type()
             if internal_type == 'DateField':
-                default = default.date
-            elif internal_type == 'TimeField':
-                default = default.time
-            elif internal_type == 'DateTimeField':
-                default = timezone.now
-        else:
-            default = None
+                return default.date
+            if internal_type == 'TimeField':
+                return default.time
+            if internal_type == 'DateTimeField':
+                return timezone.now
+
+    def effective_default(self, field):
+        """
+        Return a field's effective database default value
+        """
+        default = BaseDatabaseSchemaEditor.effective_default_before_callable(field)
         # If it's a callable, call it
         if callable(default):
             default = default()
         # Run it through the field's get_db_prep_save method so we can send it
         # to the database.
-        default = field.get_db_prep_save(default, self.connection)
-        return default
+        return field.get_db_prep_save(default, self.connection)
 
     def quote_value(self, value):
         """
@@ -616,7 +617,9 @@ class BaseDatabaseSchemaEditor:
             not new_field.null and
             old_default != new_default and
             new_default is not None and
-            not self.skip_default(new_field)
+            not self.skip_default(new_field) and
+            BaseDatabaseSchemaEditor.effective_default_before_callable(old_field) !=
+            BaseDatabaseSchemaEditor.effective_default_before_callable(new_field)
         )
         if needs_database_default:
             actions.append(self._alter_column_default_sql(model, old_field, new_field))
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index e9903a7..8e9780b 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -1229,7 +1229,12 @@ class DateField(DateTimeCheckMixin, Field):
         if self.auto_now:
             kwargs['auto_now'] = True
         if self.auto_now_add:
-            kwargs['auto_now_add'] = True
+            kwargs['auto_now_add'] = True  # This line is here solely to make test.migrations.test_autodetector.
+            # test_add_date_fields_with_auto_now_add_(not_asking_for_null_addition and asking_for_default) pass
+            # Without that line, the number of migrations in tests.migrations.test_autodetector.
+            # test_add_date_fields_with_(auto_now_add_switching_to_default,default_switching_to_auto_now_add)
+            # is reduced to zero.
+            kwargs['default'] = datetime.date.today
         if self.auto_now or self.auto_now_add:
             del kwargs['editable']
             del kwargs['blank']
@@ -1367,6 +1372,12 @@ class DateTimeField(DateField):
 
         return []
 
+    def deconstruct(self):
+        name, path, args, kwargs = super(DateTimeField, self).deconstruct()
+        if self.auto_now_add:
+            kwargs['default'] = timezone.now
+        return name, path, args, kwargs
+
     def get_internal_type(self):
         return "DateTimeField"
 
diff --git a/tests/field_deconstruction/tests.py b/tests/field_deconstruction/tests.py
index 2cf1f93..1afd95f 100644
--- a/tests/field_deconstruction/tests.py
+++ b/tests/field_deconstruction/tests.py
@@ -1,7 +1,10 @@
+from datetime import datetime
+
 from django.apps import apps
 from django.db import models
 from django.test import SimpleTestCase, override_settings
 from django.test.utils import isolate_lru_cache
+from django.utils import timezone
 
 
 class FieldDeconstructionTests(SimpleTestCase):
@@ -113,6 +116,16 @@ class FieldDeconstructionTests(SimpleTestCase):
         self.assertEqual(path, "django.db.models.DateField")
         self.assertEqual(args, [])
         self.assertEqual(kwargs, {"auto_now": True})
+        field = models.DateField(auto_now_add=True)
+        name, path, args, kwargs = field.deconstruct()
+        self.assertEqual(path, "django.db.models.DateField")
+        self.assertEqual(args, [])
+        self.assertEqual(kwargs, {"auto_now_add": True, "default": datetime.date.today})
+        field = models.DateTimeField(auto_now=True, auto_now_add=True)
+        name, path, args, kwargs = field.deconstruct()
+        self.assertEqual(path, "django.db.models.DateTimeField")
+        self.assertEqual(args, [])
+        self.assertEqual(kwargs, {"auto_now_add": True, "default": datetime.date.today, "auto_now": True})
 
     def test_datetime_field(self):
         field = models.DateTimeField()
@@ -124,13 +137,13 @@ class FieldDeconstructionTests(SimpleTestCase):
         name, path, args, kwargs = field.deconstruct()
         self.assertEqual(path, "django.db.models.DateTimeField")
         self.assertEqual(args, [])
-        self.assertEqual(kwargs, {"auto_now_add": True})
+        self.assertEqual(kwargs, {"auto_now_add": True, "default": timezone.now})
         # Bug #21785
         field = models.DateTimeField(auto_now=True, auto_now_add=True)
         name, path, args, kwargs = field.deconstruct()
         self.assertEqual(path, "django.db.models.DateTimeField")
         self.assertEqual(args, [])
-        self.assertEqual(kwargs, {"auto_now_add": True, "auto_now": True})
+        self.assertEqual(kwargs, {"auto_now_add": True, "default": timezone.now, "auto_now": True})
 
     def test_decimal_field(self):
         field = models.DecimalField(max_digits=5, decimal_places=2)
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index 43c3a19..b256e7d 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -1,3 +1,4 @@
+import datetime
 import functools
 import re
 from unittest import mock
@@ -14,6 +15,7 @@ from django.db.migrations.questioner import MigrationQuestioner
 from django.db.migrations.state import ModelState, ProjectState
 from django.test import TestCase, override_settings
 from django.test.utils import isolate_lru_cache
+from django.utils import timezone
 
 from .models import FoodManager, FoodQuerySet
 
@@ -73,6 +75,12 @@ class AutodetectorTests(TestCase):
         ("date_time_of_birth", models.DateTimeField(auto_now_add=True)),
         ("time_of_birth", models.TimeField(auto_now_add=True)),
     ])
+    author_dates_of_birth_default_timezone_now = ModelState("testapp", "Author", [
+        ("id", models.AutoField(primary_key=True)),
+        ("date_of_birth", models.DateField(default=datetime.date.today)),
+        ("date_time_of_birth", models.DateTimeField(default=timezone.now)),
+        ("time_of_birth", models.TimeField(auto_now_add=True)),
+    ])
     author_name_deconstructible_1 = ModelState("testapp", "Author", [
         ("id", models.AutoField(primary_key=True)),
         ("name", models.CharField(max_length=200, default=DeconstructibleObject())),
@@ -682,6 +690,24 @@ class AutodetectorTests(TestCase):
         self.assertOperationFieldAttributes(changes, "testapp", 0, 1, auto_now=True)
         self.assertOperationFieldAttributes(changes, "testapp", 0, 2, auto_now=True)
 
+    def test_add_date_fields_with_auto_now_add_switching_to_default(self):
+        changes = self.get_changes([self.author_dates_of_birth_default_timezone_now],
+                                   [self.author_dates_of_birth_auto_now_add])
+        # Right number/type of migrations?
+        self.assertNumberMigrations(changes, 'testapp', 1)
+        self.assertOperationTypes(changes, 'testapp', 0, ["AlterField", "AlterField"])
+        self.assertOperationAttributes(changes, "testapp", 0, 0, name="date_of_birth", preserve_default=True)
+        self.assertOperationAttributes(changes, "testapp", 0, 1, name="date_time_of_birth", preserve_default=True)
+
+    def test_add_date_fields_with_default_switching_to_auto_now_add(self):
+        changes = self.get_changes([self.author_dates_of_birth_auto_now_add],
+                                   [self.author_dates_of_birth_default_timezone_now])
+        # Right number/type of migrations?
+        self.assertNumberMigrations(changes, 'testapp', 1)
+        self.assertOperationTypes(changes, 'testapp', 0, ["AlterField", "AlterField"])
+        self.assertOperationAttributes(changes, "testapp", 0, 0, name="date_of_birth", preserve_default=True)
+        self.assertOperationAttributes(changes, "testapp", 0, 1, name="date_time_of_birth", preserve_default=True)
+
     @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition',
                 side_effect=AssertionError("Should not have prompted for not null addition"))
     def test_add_date_fields_with_auto_now_add_not_asking_for_null_addition(self, mocked_ask_method):
@@ -702,7 +728,7 @@ class AutodetectorTests(TestCase):
         self.assertOperationFieldAttributes(changes, "testapp", 0, 0, auto_now_add=True)
         self.assertOperationFieldAttributes(changes, "testapp", 0, 1, auto_now_add=True)
         self.assertOperationFieldAttributes(changes, "testapp", 0, 2, auto_now_add=True)
-        self.assertEqual(mocked_ask_method.call_count, 3)
+        self.assertEqual(mocked_ask_method.call_count, 1)
 
     def test_remove_field(self):
         """Tests autodetection of removed fields."""
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 8a77624..326d889 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -1291,13 +1291,11 @@ class MakeMigrationsTests(MigrationTestBase):
                 app_label = 'migrations'
 
         # Monkeypatch interactive questioner to auto accept
-        with mock.patch('django.db.migrations.questioner.sys.stdout', new_callable=io.StringIO) as prompt_stdout:
+        with mock.patch('django.db.migrations.questioner.sys.stdout', new_callable=io.StringIO):
             out = io.StringIO()
             with self.temporary_migration_module(module='migrations.test_auto_now_add'):
                 call_command('makemigrations', 'migrations', interactive=True, stdout=out)
             output = out.getvalue()
-            prompt_output = prompt_stdout.getvalue()
-            self.assertIn("You can accept the default 'timezone.now' by pressing 'Enter'", prompt_output)
             self.assertIn("Add field creation_date to entry", output)
 
 
