Refs #31703 -- Moved MigrationAutodetector.suggest_name() to Migration.
Allows expanding the method to inspect additional attributes of the migration instance. For example, the Migration.initial attribute.
This commit is contained in:
parent
798835112d
commit
bce180dd05
|
@ -9,9 +9,7 @@ from django.db.migrations.migration import Migration
|
|||
from django.db.migrations.operations.models import AlterModelOptions
|
||||
from django.db.migrations.optimizer import MigrationOptimizer
|
||||
from django.db.migrations.questioner import MigrationQuestioner
|
||||
from django.db.migrations.utils import (
|
||||
COMPILED_REGEX_TYPE, RegexObject, get_migration_name_timestamp,
|
||||
)
|
||||
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
|
||||
from django.utils.topological_sort import stable_topological_sort
|
||||
|
||||
|
||||
|
@ -1265,13 +1263,14 @@ class MigrationAutodetector:
|
|||
for i, migration in enumerate(migrations):
|
||||
if i == 0 and app_leaf:
|
||||
migration.dependencies.append(app_leaf)
|
||||
if i == 0 and not app_leaf:
|
||||
new_name = "0001_%s" % migration_name if migration_name else "0001_initial"
|
||||
new_name_parts = ['%04i' % next_number]
|
||||
if migration_name:
|
||||
new_name_parts.append(migration_name)
|
||||
elif i == 0 and not app_leaf:
|
||||
new_name_parts.append('initial')
|
||||
else:
|
||||
new_name = "%04i_%s" % (
|
||||
next_number,
|
||||
migration_name or self.suggest_name(migration.operations)[:100],
|
||||
)
|
||||
new_name_parts.append(migration.suggest_name()[:100])
|
||||
new_name = '_'.join(new_name_parts)
|
||||
name_map[(app_label, migration.name)] = (app_label, new_name)
|
||||
next_number += 1
|
||||
migration.name = new_name
|
||||
|
@ -1306,22 +1305,6 @@ class MigrationAutodetector:
|
|||
del changes[app_label]
|
||||
return changes
|
||||
|
||||
@classmethod
|
||||
def suggest_name(cls, ops):
|
||||
"""
|
||||
Given a set of operations, suggest a name for the migration they might
|
||||
represent. Names are not guaranteed to be unique, but put some effort
|
||||
into the fallback name to avoid VCS conflicts if possible.
|
||||
"""
|
||||
name = None
|
||||
if len(ops) == 1:
|
||||
name = ops[0].migration_name_fragment
|
||||
elif len(ops) > 1 and all(isinstance(o, operations.CreateModel) for o in ops):
|
||||
name = '_'.join(sorted(o.migration_name_fragment for o in ops))
|
||||
if name is None:
|
||||
name = 'auto_%s' % get_migration_name_timestamp()
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def parse_number(cls, name):
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.db.migrations import operations
|
||||
from django.db.migrations.utils import get_migration_name_timestamp
|
||||
from django.db.transaction import atomic
|
||||
|
||||
from .exceptions import IrreversibleError
|
||||
|
@ -175,6 +177,24 @@ class Migration:
|
|||
operation.database_backwards(self.app_label, schema_editor, from_state, to_state)
|
||||
return project_state
|
||||
|
||||
def suggest_name(self):
|
||||
"""
|
||||
Suggest a name for the operations this migration might represent. Names
|
||||
are not guaranteed to be unique, but put some effort into the fallback
|
||||
name to avoid VCS conflicts if possible.
|
||||
"""
|
||||
name = None
|
||||
if len(self.operations) == 1:
|
||||
name = self.operations[0].migration_name_fragment
|
||||
elif (
|
||||
len(self.operations) > 1 and
|
||||
all(isinstance(o, operations.CreateModel) for o in self.operations)
|
||||
):
|
||||
name = '_'.join(sorted(o.migration_name_fragment for o in self.operations))
|
||||
if name is None:
|
||||
name = 'auto_%s' % get_migration_name_timestamp()
|
||||
return name
|
||||
|
||||
|
||||
class SwappableTuple(tuple):
|
||||
"""
|
||||
|
|
|
@ -2481,25 +2481,39 @@ class AutodetectorTests(TestCase):
|
|||
self.assertOperationAttributes(changes, 'app', 0, 1, name='book')
|
||||
|
||||
|
||||
class AutodetectorSuggestNameTests(SimpleTestCase):
|
||||
class MigrationSuggestNameTests(SimpleTestCase):
|
||||
def test_single_operation(self):
|
||||
ops = [migrations.CreateModel('Person', fields=[])]
|
||||
self.assertEqual(MigrationAutodetector.suggest_name(ops), 'person')
|
||||
ops = [migrations.DeleteModel('Person')]
|
||||
self.assertEqual(MigrationAutodetector.suggest_name(ops), 'delete_person')
|
||||
class Migration(migrations.Migration):
|
||||
operations = [migrations.CreateModel('Person', fields=[])]
|
||||
|
||||
migration = Migration('0001_initial', 'test_app')
|
||||
self.assertEqual(migration.suggest_name(), 'person')
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
operations = [migrations.DeleteModel('Person')]
|
||||
|
||||
migration = Migration('0002_initial', 'test_app')
|
||||
self.assertEqual(migration.suggest_name(), 'delete_person')
|
||||
|
||||
def test_two_create_models(self):
|
||||
ops = [
|
||||
class Migration(migrations.Migration):
|
||||
operations = [
|
||||
migrations.CreateModel('Person', fields=[]),
|
||||
migrations.CreateModel('Animal', fields=[]),
|
||||
]
|
||||
self.assertEqual(MigrationAutodetector.suggest_name(ops), 'animal_person')
|
||||
|
||||
migration = Migration('0001_initial', 'test_app')
|
||||
self.assertEqual(migration.suggest_name(), 'animal_person')
|
||||
|
||||
def test_none_name(self):
|
||||
ops = [migrations.RunSQL('SELECT 1 FROM person;')]
|
||||
suggest_name = MigrationAutodetector.suggest_name(ops)
|
||||
class Migration(migrations.Migration):
|
||||
operations = [migrations.RunSQL('SELECT 1 FROM person;')]
|
||||
|
||||
migration = Migration('0001_initial', 'test_app')
|
||||
suggest_name = migration.suggest_name()
|
||||
self.assertIs(suggest_name.startswith('auto_'), True)
|
||||
|
||||
def test_auto(self):
|
||||
suggest_name = MigrationAutodetector.suggest_name([])
|
||||
migration = migrations.Migration('0001_initial', 'test_app')
|
||||
suggest_name = migration.suggest_name()
|
||||
self.assertIs(suggest_name.startswith('auto_'), True)
|
||||
|
|
Loading…
Reference in New Issue