mirror of
https://github.com/django/django.git
synced 2025-05-16 03:46:28 +00:00
Fixed #23302 -- Added --name/-n option to makemigrations command
This commit is contained in:
parent
bda2809712
commit
1435cfbe8d
@ -28,6 +28,8 @@ class Command(BaseCommand):
|
|||||||
help="Create an empty migration.")
|
help="Create an empty migration.")
|
||||||
parser.add_argument('--noinput', action='store_false', dest='interactive', default=True,
|
parser.add_argument('--noinput', action='store_false', dest='interactive', default=True,
|
||||||
help='Tells Django to NOT prompt the user for input of any kind.')
|
help='Tells Django to NOT prompt the user for input of any kind.')
|
||||||
|
parser.add_argument('-n', '--name', action='store', dest='name', default=None,
|
||||||
|
help="Use this name for migration file(s).")
|
||||||
|
|
||||||
def handle(self, *app_labels, **options):
|
def handle(self, *app_labels, **options):
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ class Command(BaseCommand):
|
|||||||
self.dry_run = options.get('dry_run', False)
|
self.dry_run = options.get('dry_run', False)
|
||||||
self.merge = options.get('merge', False)
|
self.merge = options.get('merge', False)
|
||||||
self.empty = options.get('empty', False)
|
self.empty = options.get('empty', False)
|
||||||
|
self.migration_name = options.get('name', None)
|
||||||
|
|
||||||
# Make sure the app they asked for exists
|
# Make sure the app they asked for exists
|
||||||
app_labels = set(app_labels)
|
app_labels = set(app_labels)
|
||||||
@ -98,7 +101,11 @@ class Command(BaseCommand):
|
|||||||
(app, [Migration("custom", app)])
|
(app, [Migration("custom", app)])
|
||||||
for app in app_labels
|
for app in app_labels
|
||||||
)
|
)
|
||||||
changes = autodetector.arrange_for_graph(changes, loader.graph)
|
changes = autodetector.arrange_for_graph(
|
||||||
|
changes=changes,
|
||||||
|
graph=loader.graph,
|
||||||
|
migration_name=self.migration_name,
|
||||||
|
)
|
||||||
self.write_migration_files(changes)
|
self.write_migration_files(changes)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -107,6 +114,7 @@ class Command(BaseCommand):
|
|||||||
graph=loader.graph,
|
graph=loader.graph,
|
||||||
trim_to_apps=app_labels or None,
|
trim_to_apps=app_labels or None,
|
||||||
convert_apps=app_labels or None,
|
convert_apps=app_labels or None,
|
||||||
|
migration_name=self.migration_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
# No changes? Tell them.
|
# No changes? Tell them.
|
||||||
|
@ -31,14 +31,14 @@ class MigrationAutodetector(object):
|
|||||||
self.to_state = to_state
|
self.to_state = to_state
|
||||||
self.questioner = questioner or MigrationQuestioner()
|
self.questioner = questioner or MigrationQuestioner()
|
||||||
|
|
||||||
def changes(self, graph, trim_to_apps=None, convert_apps=None):
|
def changes(self, graph, trim_to_apps=None, convert_apps=None, migration_name=None):
|
||||||
"""
|
"""
|
||||||
Main entry point to produce a list of appliable changes.
|
Main entry point to produce a list of appliable changes.
|
||||||
Takes a graph to base names on and an optional set of apps
|
Takes a graph to base names on and an optional set of apps
|
||||||
to try and restrict to (restriction is not guaranteed)
|
to try and restrict to (restriction is not guaranteed)
|
||||||
"""
|
"""
|
||||||
changes = self._detect_changes(convert_apps, graph)
|
changes = self._detect_changes(convert_apps, graph)
|
||||||
changes = self.arrange_for_graph(changes, graph)
|
changes = self.arrange_for_graph(changes, graph, migration_name)
|
||||||
if trim_to_apps:
|
if trim_to_apps:
|
||||||
changes = self._trim_to_apps(changes, trim_to_apps)
|
changes = self._trim_to_apps(changes, trim_to_apps)
|
||||||
return changes
|
return changes
|
||||||
@ -951,7 +951,7 @@ class MigrationAutodetector(object):
|
|||||||
dependencies=dependencies,
|
dependencies=dependencies,
|
||||||
)
|
)
|
||||||
|
|
||||||
def arrange_for_graph(self, changes, graph):
|
def arrange_for_graph(self, changes, graph, migration_name=None):
|
||||||
"""
|
"""
|
||||||
Takes in a result from changes() and a MigrationGraph,
|
Takes in a result from changes() and a MigrationGraph,
|
||||||
and fixes the names and dependencies of the changes so they
|
and fixes the names and dependencies of the changes so they
|
||||||
@ -985,11 +985,11 @@ class MigrationAutodetector(object):
|
|||||||
if i == 0 and app_leaf:
|
if i == 0 and app_leaf:
|
||||||
migration.dependencies.append(app_leaf)
|
migration.dependencies.append(app_leaf)
|
||||||
if i == 0 and not app_leaf:
|
if i == 0 and not app_leaf:
|
||||||
new_name = "0001_initial"
|
new_name = "0001_%s" % migration_name if migration_name else "0001_initial"
|
||||||
else:
|
else:
|
||||||
new_name = "%04i_%s" % (
|
new_name = "%04i_%s" % (
|
||||||
next_number,
|
next_number,
|
||||||
self.suggest_name(migration.operations)[:100],
|
migration_name or self.suggest_name(migration.operations)[:100],
|
||||||
)
|
)
|
||||||
name_map[(app_label, migration.name)] = (app_label, new_name)
|
name_map[(app_label, migration.name)] = (app_label, new_name)
|
||||||
next_number += 1
|
next_number += 1
|
||||||
|
@ -683,6 +683,13 @@ written.
|
|||||||
|
|
||||||
The ``--merge`` option enables fixing of migration conflicts.
|
The ``--merge`` option enables fixing of migration conflicts.
|
||||||
|
|
||||||
|
.. django-admin-option:: --name, -n
|
||||||
|
|
||||||
|
.. versionadded:: 1.8
|
||||||
|
|
||||||
|
The ``--name`` option allows you to give the migration(s) a custom name instead
|
||||||
|
of a generated one.
|
||||||
|
|
||||||
migrate [<app_label> [<migrationname>]]
|
migrate [<app_label> [<migrationname>]]
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
@ -228,6 +228,9 @@ Management Commands
|
|||||||
* The :djadmin:`dbshell` command now supports MySQL's optional SSL certificate
|
* The :djadmin:`dbshell` command now supports MySQL's optional SSL certificate
|
||||||
authority setting (``--ssl-ca``).
|
authority setting (``--ssl-ca``).
|
||||||
|
|
||||||
|
* The :djadminopt:`--name` option for :djadmin:`makemigrations` allows you to
|
||||||
|
to give the migration(s) a custom name instead of a generated one.
|
||||||
|
|
||||||
Models
|
Models
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
|
7
docs/topics/migrations.txt
Executable file → Normal file
7
docs/topics/migrations.txt
Executable file → Normal file
@ -309,6 +309,13 @@ Note that this only works given two things:
|
|||||||
that your database doesn't match your models, you'll just get errors when
|
that your database doesn't match your models, you'll just get errors when
|
||||||
migrations try to modify those tables.
|
migrations try to modify those tables.
|
||||||
|
|
||||||
|
.. versionadded:: 1.8
|
||||||
|
|
||||||
|
If you want to give the migration(s) a meaningful name instead of a generated one,
|
||||||
|
you can use the :djadminopt:`--name` option::
|
||||||
|
|
||||||
|
$ python manage.py makemigrations --name changed_my_model your_app_label
|
||||||
|
|
||||||
.. _historical-models:
|
.. _historical-models:
|
||||||
|
|
||||||
Historical models
|
Historical models
|
||||||
|
@ -188,6 +188,31 @@ class AutodetectorTests(TestCase):
|
|||||||
self.assertEqual(changes["otherapp"][0].name, "0001_initial")
|
self.assertEqual(changes["otherapp"][0].name, "0001_initial")
|
||||||
self.assertNotIn("thirdapp", changes)
|
self.assertNotIn("thirdapp", changes)
|
||||||
|
|
||||||
|
def test_custom_migration_name(self):
|
||||||
|
"Tests custom naming of migrations for graph matching."
|
||||||
|
# Make a fake graph
|
||||||
|
graph = MigrationGraph()
|
||||||
|
graph.add_node(("testapp", "0001_initial"), None)
|
||||||
|
graph.add_node(("testapp", "0002_foobar"), None)
|
||||||
|
graph.add_node(("otherapp", "0001_initial"), None)
|
||||||
|
graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial"))
|
||||||
|
|
||||||
|
# Use project state to make a new migration change set
|
||||||
|
before = self.make_project_state([])
|
||||||
|
after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable])
|
||||||
|
autodetector = MigrationAutodetector(before, after)
|
||||||
|
changes = autodetector._detect_changes()
|
||||||
|
|
||||||
|
# Run through arrange_for_graph
|
||||||
|
migration_name = 'custom_name'
|
||||||
|
changes = autodetector.arrange_for_graph(changes, graph, migration_name)
|
||||||
|
|
||||||
|
# Make sure there's a new name, deps match, etc.
|
||||||
|
self.assertEqual(changes["testapp"][0].name, "0003_%s" % migration_name)
|
||||||
|
self.assertEqual(changes["testapp"][0].dependencies, [("testapp", "0002_foobar")])
|
||||||
|
self.assertEqual(changes["otherapp"][0].name, "0002_%s" % migration_name)
|
||||||
|
self.assertEqual(changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")])
|
||||||
|
|
||||||
def test_new_model(self):
|
def test_new_model(self):
|
||||||
"Tests autodetection of new models"
|
"Tests autodetection of new models"
|
||||||
# Make state
|
# Make state
|
||||||
|
@ -546,3 +546,34 @@ class MakeMigrationsTests(MigrationTestBase):
|
|||||||
questioner.input = old_input
|
questioner.input = old_input
|
||||||
if os.path.exists(merge_file):
|
if os.path.exists(merge_file):
|
||||||
os.remove(merge_file)
|
os.remove(merge_file)
|
||||||
|
|
||||||
|
@override_system_checks([])
|
||||||
|
def test_makemigrations_with_custom_name(self):
|
||||||
|
"""
|
||||||
|
Makes sure that makemigrations generate a custom migration.
|
||||||
|
"""
|
||||||
|
def cmd(migration_count, migration_name, *args):
|
||||||
|
with override_settings(MIGRATION_MODULES={"migrations": self.migration_pkg}):
|
||||||
|
try:
|
||||||
|
call_command("makemigrations", "migrations", "--verbosity", "0", "--name", migration_name, *args)
|
||||||
|
except CommandError:
|
||||||
|
self.fail("Makemigrations errored in creating empty migration with custom name for a proper app.")
|
||||||
|
migration_file = os.path.join(self.migration_dir, "%s_%s.py" % (migration_count, migration_name))
|
||||||
|
# Check for existing migration file in migration folder
|
||||||
|
self.assertTrue(os.path.exists(migration_file))
|
||||||
|
with codecs.open(migration_file, "r", encoding="utf-8") as fp:
|
||||||
|
content = fp.read()
|
||||||
|
self.assertTrue("# -*- coding: utf-8 -*-" in content)
|
||||||
|
content = content.replace(" ", "")
|
||||||
|
return content
|
||||||
|
|
||||||
|
# generate an initial migration
|
||||||
|
migration_name_0001 = "my_initial_migration"
|
||||||
|
content = cmd("0001", migration_name_0001)
|
||||||
|
self.assertIn("dependencies=[\n]", content)
|
||||||
|
|
||||||
|
# generate an empty migration
|
||||||
|
migration_name_0002 = "my_custom_migration"
|
||||||
|
content = cmd("0002", migration_name_0002, "--empty")
|
||||||
|
self.assertIn("dependencies=[\n('migrations','0001_%s'),\n]" % migration_name_0001, content)
|
||||||
|
self.assertIn("operations=[\n]", content)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user