Commit 41b337ef authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #23630 -- Made AlterModelTable rename auto-created M2M tables.

Thanks Naddiseo for the report, Andrew Godwin for guidance,
and Shai Berger for review.
parent 22c85bf1
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -212,6 +212,14 @@ class AlterModelTable(Operation):
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Rename M2M fields whose name is based on this model's db_table
            for (old_field, new_field) in zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many):
                if new_field.rel.through._meta.auto_created:
                    schema_editor.alter_db_table(
                        new_field.rel.through,
                        old_field.rel.through._meta.db_table,
                        new_field.rel.through._meta.db_table,
                    )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        return self.database_forwards(app_label, schema_editor, from_state, to_state)
+2 −1
Original line number Diff line number Diff line
@@ -9,4 +9,5 @@ Django 1.7.2 fixes several bugs in 1.7.1.
Bugfixes
========

* ... (:ticket:`00000`).
* Fixed migration's renaming of auto-created many-to-many tables when changing
  :attr:`Meta.db_table <django.db.models.Options.db_table>` (:ticket:`23630`).
+36 −1
Original line number Diff line number Diff line
@@ -46,7 +46,9 @@ class OperationTestBase(MigrationTestBase):
        operation.state_forwards(app_label, new_state)
        return project_state, new_state

    def set_up_test_model(self, app_label, second_model=False, third_model=False, related_model=False, mti_model=False, proxy_model=False, unique_together=False, options=False):
    def set_up_test_model(self, app_label, second_model=False, third_model=False,
            related_model=False, mti_model=False, proxy_model=False,
            unique_together=False, options=False, db_table=None):
        """
        Creates a test model state and database table.
        """
@@ -82,6 +84,8 @@ class OperationTestBase(MigrationTestBase):
        }
        if options:
            model_options["permissions"] = [("can_groom", "Can groom")]
        if db_table:
            model_options["db_table"] = db_table
        operations = [migrations.CreateModel(
            "Pony",
            [
@@ -875,6 +879,37 @@ class OperationTests(OperationTestBase):
            operation.database_backwards("test_almota", editor, new_state, project_state)
        self.assertTableExists("test_almota_pony")

    def test_alter_model_table_m2m(self):
        """
        AlterModelTable should rename auto-generated M2M tables.
        """
        app_label = "test_talflmltlm2m"
        pony_db_table = 'pony_foo'
        project_state = self.set_up_test_model(app_label, second_model=True, db_table=pony_db_table)
        # Add the M2M field
        first_state = project_state.clone()
        operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable"))
        operation.state_forwards(app_label, first_state)
        with connection.schema_editor() as editor:
            operation.database_forwards(app_label, editor, project_state, first_state)
        original_m2m_table = "%s_%s" % (pony_db_table, "stables")
        new_m2m_table = "%s_%s" % (app_label, "pony_stables")
        self.assertTableExists(original_m2m_table)
        self.assertTableNotExists(new_m2m_table)
        # Rename the Pony db_table which should also rename the m2m table.
        second_state = first_state.clone()
        operation = migrations.AlterModelTable(name='pony', table=None)
        operation.state_forwards(app_label, second_state)
        with connection.schema_editor() as editor:
            operation.database_forwards(app_label, editor, first_state, second_state)
        self.assertTableExists(new_m2m_table)
        self.assertTableNotExists(original_m2m_table)
        # And test reversal
        with connection.schema_editor() as editor:
            operation.database_backwards(app_label, editor, second_state, first_state)
        self.assertTableExists(original_m2m_table)
        self.assertTableNotExists(new_m2m_table)

    def test_alter_field(self):
        """
        Tests the AlterField operation.