summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoayad Mardini <moayad.m@gmail.com>2014-05-22 12:42:46 +0300
committerTim Graham <timograham@gmail.com>2014-05-24 09:56:18 -0400
commit63fc91b3cac523690655c1d86d09972e0cc3a29d (patch)
tree725af3ee0012a51357e76326653a7e7aad303438
parent9fb0f5dddc4cf7f2d294af1bcde2c359cffd90a5 (diff)
Fixed #22676 -- makemigrations --dry-run should not ask for defaults
Made the fix in InteractiveMigrationQuestioner class code, rather than MigrationAutodetector, because --dry-run shouldn't affect whether MigrationAutodetector will detect non-nullable fields, but the questioner should skip the question and returns a None for default (since that won't be used anyway) if --dry-run is used.
-rw-r--r--django/core/management/commands/makemigrations.py2
-rw-r--r--django/db/migrations/questioner.py67
-rw-r--r--tests/migrations/test_commands.py20
-rw-r--r--tests/migrations/test_migrations_no_default/0001_initial.py23
-rw-r--r--tests/migrations/test_migrations_no_default/__init__.py0
5 files changed, 79 insertions, 33 deletions
diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py
index 84a4d59fe2..97661ea8b5 100644
--- a/django/core/management/commands/makemigrations.py
+++ b/django/core/management/commands/makemigrations.py
@@ -77,7 +77,7 @@ class Command(BaseCommand):
autodetector = MigrationAutodetector(
loader.project_state(),
ProjectState.from_apps(apps),
- InteractiveMigrationQuestioner(specified_apps=app_labels),
+ InteractiveMigrationQuestioner(specified_apps=app_labels, dry_run=self.dry_run),
)
# If they want to make an empty migration, make one for each app
diff --git a/django/db/migrations/questioner.py b/django/db/migrations/questioner.py
index 4619bd616a..0476ba749f 100644
--- a/django/db/migrations/questioner.py
+++ b/django/db/migrations/questioner.py
@@ -18,9 +18,10 @@ class MigrationQuestioner(object):
interactive subclass is what the command-line arguments will use.
"""
- def __init__(self, defaults=None, specified_apps=None):
+ def __init__(self, defaults=None, specified_apps=None, dry_run=None):
self.defaults = defaults or {}
self.specified_apps = specified_apps or set()
+ self.dry_run = dry_run
def ask_initial(self, app_label):
"Should we create an initial migration for the app?"
@@ -93,37 +94,39 @@ class InteractiveMigrationQuestioner(MigrationQuestioner):
def ask_not_null_addition(self, field_name, model_name):
"Adding a NOT NULL field to a model"
- choice = self._choice_input(
- "You are trying to add a non-nullable field '%s' to %s without a default;\n" % (field_name, model_name) +
- "we can't do that (the database needs something to populate existing rows).\n" +
- "Please select a fix:",
- [
- "Provide a one-off default now (will be set on all existing rows)",
- "Quit, and let me add a default in models.py",
- ]
- )
- if choice == 2:
- sys.exit(3)
- else:
- print("Please enter the default value now, as valid Python")
- print("The datetime module is available, so you can do e.g. datetime.date.today()")
- while True:
- if six.PY3:
- # Six does not correctly abstract over the fact that
- # py3 input returns a unicode string, while py2 raw_input
- # returns a bytestring.
- code = input(">>> ")
- else:
- code = input(">>> ").decode(sys.stdin.encoding)
- if not code:
- print("Please enter some code, or 'exit' (with no quotes) to exit.")
- elif code == "exit":
- sys.exit(1)
- else:
- try:
- return eval(code, {}, {"datetime": datetime_safe})
- except (SyntaxError, NameError) as e:
- print("Invalid input: %s" % e)
+ if not self.dry_run:
+ choice = self._choice_input(
+ "You are trying to add a non-nullable field '%s' to %s without a default;\n" % (field_name, model_name) +
+ "we can't do that (the database needs something to populate existing rows).\n" +
+ "Please select a fix:",
+ [
+ "Provide a one-off default now (will be set on all existing rows)",
+ "Quit, and let me add a default in models.py",
+ ]
+ )
+ if choice == 2:
+ sys.exit(3)
+ else:
+ print("Please enter the default value now, as valid Python")
+ print("The datetime module is available, so you can do e.g. datetime.date.today()")
+ while True:
+ if six.PY3:
+ # Six does not correctly abstract over the fact that
+ # py3 input returns a unicode string, while py2 raw_input
+ # returns a bytestring.
+ code = input(">>> ")
+ else:
+ code = input(">>> ").decode(sys.stdin.encoding)
+ if not code:
+ print("Please enter some code, or 'exit' (with no quotes) to exit.")
+ elif code == "exit":
+ sys.exit(1)
+ else:
+ try:
+ return eval(code, {}, {"datetime": datetime_safe})
+ except (SyntaxError, NameError) as e:
+ print("Invalid input: %s" % e)
+ return None
def ask_rename(self, model_name, old_name, new_name, field_instance):
"Was this field really renamed?"
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 757d69995b..2f78ee27a4 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -6,6 +6,7 @@ import os
import shutil
from django.apps import apps
+from django.db import models
from django.core.management import call_command, CommandError
from django.db.migrations import questioner
from django.test import override_settings, override_system_checks
@@ -362,3 +363,22 @@ class MakeMigrationsTests(MigrationTestBase):
self.assertIn("Merging migrations", stdout.getvalue())
self.assertIn("Branch 0002_second", stdout.getvalue())
self.assertIn("Branch 0002_conflicting_second", stdout.getvalue())
+
+ @override_system_checks([])
+ @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_default"})
+ def test_makemigrations_dry_run(self):
+ """
+ Ticket #22676 -- `makemigrations --dry-run` should not ask for defaults.
+ """
+
+ class SillyModel(models.Model):
+ silly_field = models.BooleanField(default=False)
+ silly_date = models.DateField() # Added field without a default
+
+ class Meta:
+ app_label = "migrations"
+
+ stdout = six.StringIO()
+ call_command("makemigrations", "migrations", dry_run=True, stdout=stdout)
+ # Output the expected changes directly, without asking for defaults
+ self.assertIn("Add field silly_date to sillymodel", stdout.getvalue())
diff --git a/tests/migrations/test_migrations_no_default/0001_initial.py b/tests/migrations/test_migrations_no_default/0001_initial.py
new file mode 100644
index 0000000000..c30910e056
--- /dev/null
+++ b/tests/migrations/test_migrations_no_default/0001_initial.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SillyModel',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('silly_field', models.BooleanField(default=False)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ ]
diff --git a/tests/migrations/test_migrations_no_default/__init__.py b/tests/migrations/test_migrations_no_default/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/migrations/test_migrations_no_default/__init__.py