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.
This commit is contained in:
parent
9fb0f5dddc
commit
63fc91b3ca
|
@ -77,7 +77,7 @@ class Command(BaseCommand):
|
||||||
autodetector = MigrationAutodetector(
|
autodetector = MigrationAutodetector(
|
||||||
loader.project_state(),
|
loader.project_state(),
|
||||||
ProjectState.from_apps(apps),
|
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
|
# If they want to make an empty migration, make one for each app
|
||||||
|
|
|
@ -18,9 +18,10 @@ class MigrationQuestioner(object):
|
||||||
interactive subclass is what the command-line arguments will use.
|
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.defaults = defaults or {}
|
||||||
self.specified_apps = specified_apps or set()
|
self.specified_apps = specified_apps or set()
|
||||||
|
self.dry_run = dry_run
|
||||||
|
|
||||||
def ask_initial(self, app_label):
|
def ask_initial(self, app_label):
|
||||||
"Should we create an initial migration for the app?"
|
"Should we create an initial migration for the app?"
|
||||||
|
@ -93,6 +94,7 @@ class InteractiveMigrationQuestioner(MigrationQuestioner):
|
||||||
|
|
||||||
def ask_not_null_addition(self, field_name, model_name):
|
def ask_not_null_addition(self, field_name, model_name):
|
||||||
"Adding a NOT NULL field to a model"
|
"Adding a NOT NULL field to a model"
|
||||||
|
if not self.dry_run:
|
||||||
choice = self._choice_input(
|
choice = self._choice_input(
|
||||||
"You are trying to add a non-nullable field '%s' to %s without a default;\n" % (field_name, model_name) +
|
"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" +
|
"we can't do that (the database needs something to populate existing rows).\n" +
|
||||||
|
@ -124,6 +126,7 @@ class InteractiveMigrationQuestioner(MigrationQuestioner):
|
||||||
return eval(code, {}, {"datetime": datetime_safe})
|
return eval(code, {}, {"datetime": datetime_safe})
|
||||||
except (SyntaxError, NameError) as e:
|
except (SyntaxError, NameError) as e:
|
||||||
print("Invalid input: %s" % e)
|
print("Invalid input: %s" % e)
|
||||||
|
return None
|
||||||
|
|
||||||
def ask_rename(self, model_name, old_name, new_name, field_instance):
|
def ask_rename(self, model_name, old_name, new_name, field_instance):
|
||||||
"Was this field really renamed?"
|
"Was this field really renamed?"
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
from django.db import models
|
||||||
from django.core.management import call_command, CommandError
|
from django.core.management import call_command, CommandError
|
||||||
from django.db.migrations import questioner
|
from django.db.migrations import questioner
|
||||||
from django.test import override_settings, override_system_checks
|
from django.test import override_settings, override_system_checks
|
||||||
|
@ -362,3 +363,22 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
self.assertIn("Merging migrations", stdout.getvalue())
|
self.assertIn("Merging migrations", stdout.getvalue())
|
||||||
self.assertIn("Branch 0002_second", stdout.getvalue())
|
self.assertIn("Branch 0002_second", stdout.getvalue())
|
||||||
self.assertIn("Branch 0002_conflicting_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())
|
||||||
|
|
|
@ -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,),
|
||||||
|
),
|
||||||
|
]
|
Loading…
Reference in New Issue