Skip to content

Commit

Permalink
Further work.
Browse files Browse the repository at this point in the history
  • Loading branch information
charettes committed Jan 27, 2025
1 parent b02dc91 commit 5e3949d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 9 deletions.
44 changes: 35 additions & 9 deletions syzygy/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,9 @@ def _create_instead_of_triggers(schema_editor, view_name, model):
)

@staticmethod
def _get_view_name(app_label, alias_name):
def _get_truncated_name(app_label: str, name: str) -> str:
return truncate_name(
"%s_%s" % (app_label, alias_name.lower()),
f"{app_label}_{name.lower()}",
connection.ops.max_name_length(),
)

Expand All @@ -436,7 +436,7 @@ def _create_view(cls, schema_editor, model, alias_name):
# XXX: Explicitly use connection to retrieve ops.max_name_length() and
# not schema_editor.connection as Django systematically use the default
# connection (see https://code.djangoproject.com/ticket/13528).
view_name = cls._get_view_name(model._meta.app_label, alias_name)
view_name = cls._get_truncated_name(model._meta.app_label, alias_name)
quote = schema_editor.quote_name
schema_editor.execute(
"CREATE VIEW {} AS SELECT * FROM {}".format(
Expand Down Expand Up @@ -465,7 +465,7 @@ def alias_model(cls, schema_editor, model, alias_name):
cls._create_view(schema_editor, model, alias_name)

def unalias_model(cls, schema_editor, model, alias_name):
view_name = cls._get_view_name(model._meta.app_label, alias_name)
view_name = cls._get_truncated_name(model._meta.app_label, alias_name)
for many_to_many in model._meta.local_many_to_many:
through = many_to_many.remote_field.through
if through._meta.auto_created:
Expand Down Expand Up @@ -539,14 +539,40 @@ class RenameAliasedModel(AliasOperationMixin, operations.RenameModel):
stage = Stage.POST_DEPLOY

def state_forwards(self, app_label, state):
state.remove_model(app_label, self.new_name)
state.remove_model(app_label, self.new_name_lower)
super().state_forwards(app_label, state)

def database_forwards(self, app_label, schema_editor, from_state, to_state):
to_model = to_state.apps.get_model(app_label, self.new_name)
if not self.allow_migrate_model(schema_editor.connection.alias, to_model):
from_model = from_state.apps.get_model(app_label, self.old_name)
if not self.allow_migrate_model(schema_editor.connection.alias, from_model):
return
self.unalias_model(schema_editor, to_model, self.alias_name)
if schema_editor.connection.vendor == "mysql":
quote_name = schema_editor.quote_name
old_name = self._get_truncated_name(app_label, self.old_name)
new_name = self._get_truncated_name(app_label, self.new_name)
defunct_name = self._get_truncated_name(
app_label, f"{self.new_name}_defunct"
)
schema_editor.execute(
"RENAME TABLE %s TO %s, %s TO %s, %s TO %s"
% (
quote_name(new_name),
quote_name(defunct_name),
quote_name(old_name),
quote_name(new_name),
quote_name(defunct_name),
quote_name(old_name),
)
)
# Simulate that the `from_state` already had the proper `db_table`
# assigned to prevent super() from attempting a RENAME.
from_state = from_state.clone()
from_state.models[app_label, self.old_name_lower].options[
"db_table"
] = new_name
from_state.apps.clear_cache()
from_state.reload_model(app_label, self.old_name_lower)
self.unalias_model(schema_editor, from_model, self.old_name)
super().database_forwards(app_label, schema_editor, from_state, to_state)

def database_backwards(self, app_label, schema_editor, from_state, to_state):
Expand All @@ -557,4 +583,4 @@ def database_backwards(self, app_label, schema_editor, from_state, to_state):
self.alias_model(schema_editor, from_model, self.alias_name)

def describe(self):
return f"Rename model {self.name} to {self.alias_name}"
return f"Rename model {self.old_name} to {self.new_name}"
23 changes: 23 additions & 0 deletions tests/test_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,26 @@ def test_elidable(self):
self.assert_optimizes_to(
operations, [migrations.RenameModel(model_name, new_model_name)]
)


class RenameAliasedModelTests(OperationTestCase):
def _apply_forwards(self):
model_name = "TestModel"
new_model_name = "NewTestModel"
field = models.IntegerField()
pre_state = self.apply_operations(
[
migrations.CreateModel(model_name, [("foo", field)]),
AliasModel(model_name, new_model_name),
]
)
post_state = self.apply_operations(
[
RenameAliasedModel(model_name, new_model_name),
],
pre_state,
)
return (pre_state, model_name), (post_state, new_model_name)

def test_database_forward(self):
(pre_state, _), (post_state, new_model_name) = self._apply_forwards()

0 comments on commit 5e3949d

Please sign in to comment.