diff --git a/CHANGELOG.md b/CHANGELOG.md index e612e03..5939cb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Fix rename field on the field add. (#134) - Fix postgres field type change error. (#135) - Fix inspectdb for `FloatField`. (#138) +- Support `rename table`. (#139) ### 0.5.1 diff --git a/aerich/ddl/__init__.py b/aerich/ddl/__init__.py index 441141e..403bfc2 100644 --- a/aerich/ddl/__init__.py +++ b/aerich/ddl/__init__.py @@ -26,6 +26,7 @@ class BaseDDL: _CHANGE_COLUMN_TEMPLATE = ( 'ALTER TABLE "{table_name}" CHANGE {old_column_name} {new_column_name} {new_column_type}' ) + _RENAME_TABLE_TEMPLATE = 'ALTER TABLE "{old_table_name}" RENAME TO "{new_table_name}"' def __init__(self, client: "BaseDBAsyncClient"): self.client = client @@ -230,3 +231,9 @@ def alter_column_null(self, model: "Type[Model]", field_describe: dict): def set_comment(self, model: "Type[Model]", field_describe: dict): raise NotImplementedError + + def rename_table(self, model: "Type[Model]", old_table_name: str, new_table_name: str): + db_table = model._meta.db_table + return self._RENAME_TABLE_TEMPLATE.format( + table_name=db_table, old_table_name=old_table_name, new_table_name=new_table_name + ) diff --git a/aerich/ddl/mysql/__init__.py b/aerich/ddl/mysql/__init__.py index d6aa1fa..57e607a 100644 --- a/aerich/ddl/mysql/__init__.py +++ b/aerich/ddl/mysql/__init__.py @@ -28,6 +28,7 @@ class MysqlDDL(BaseDDL): _DROP_FK_TEMPLATE = "ALTER TABLE `{table_name}` DROP FOREIGN KEY `{fk_name}`" _M2M_TABLE_TEMPLATE = "CREATE TABLE `{table_name}` (`{backward_key}` {backward_type} NOT NULL REFERENCES `{backward_table}` (`{backward_field}`) ON DELETE CASCADE,`{forward_key}` {forward_type} NOT NULL REFERENCES `{forward_table}` (`{forward_field}`) ON DELETE CASCADE){extra}{comment}" _MODIFY_COLUMN_TEMPLATE = "ALTER TABLE `{table_name}` MODIFY COLUMN {column}" + _RENAME_TABLE_TEMPLATE = "ALTER TABLE `{old_table_name}` RENAME TO `{new_table_name}`" def alter_column_null(self, model: "Type[Model]", field_describe: dict): raise NotSupportError("Alter column null is unsupported in MySQL.") diff --git a/aerich/migrate.py b/aerich/migrate.py index 8f842fe..eb06b5e 100644 --- a/aerich/migrate.py +++ b/aerich/migrate.py @@ -176,7 +176,11 @@ def diff_models(cls, old_models: Dict[str, dict], new_models: Dict[str, dict], u pass else: old_model_describe = old_models.get(new_model_str) - + # rename table + new_table = new_model_describe.get("table") + old_table = old_model_describe.get("table") + if new_table != old_table: + cls._add_operator(cls.rename_table(model, old_table, new_table), upgrade) old_unique_together = set( map(lambda x: tuple(x), old_model_describe.get("unique_together")) ) @@ -406,6 +410,10 @@ def diff_models(cls, old_models: Dict[str, dict], new_models: Dict[str, dict], u if old_model not in new_models.keys(): cls._add_operator(cls.drop_model(old_models.get(old_model).get("table")), upgrade) + @classmethod + def rename_table(cls, model: Type[Model], old_table_name: str, new_table_name: str): + return cls.ddl.rename_table(model, old_table_name, new_table_name) + @classmethod def add_model(cls, model: Type[Model]): return cls.ddl.create_table(model) diff --git a/tests/old_models.py b/tests/old_models.py index ef0fd66..3a25337 100644 --- a/tests/old_models.py +++ b/tests/old_models.py @@ -61,3 +61,6 @@ class Config(Model): key = fields.CharField(max_length=20) value = fields.JSONField() status: Status = fields.IntEnumField(Status, default=Status.on) + + class Meta: + table = "configs" diff --git a/tests/test_migrate.py b/tests/test_migrate.py index 54d806d..20ac113 100644 --- a/tests/test_migrate.py +++ b/tests/test_migrate.py @@ -146,7 +146,7 @@ "models.Config": { "name": "models.Config", "app": "models", - "table": "config", + "table": "configs", "abstract": False, "description": None, "docstring": None, @@ -790,6 +790,7 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `config` ALTER COLUMN `status` DROP DEFAULT", "ALTER TABLE `email` ADD `address` VARCHAR(200) NOT NULL", "ALTER TABLE `email` DROP COLUMN `user_id`", + "ALTER TABLE `configs` RENAME TO `config`", "ALTER TABLE `product` RENAME COLUMN `image` TO `pic`", "ALTER TABLE `email` RENAME COLUMN `id` TO `email_id`", "ALTER TABLE `email` DROP FOREIGN KEY `fk_email_user_5b58673d`", @@ -813,6 +814,7 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `config` ALTER COLUMN `status` SET DEFAULT 1", "ALTER TABLE `email` ADD `user_id` INT NOT NULL", "ALTER TABLE `email` DROP COLUMN `address`", + "ALTER TABLE `config` RENAME TO `configs`", "ALTER TABLE `product` RENAME COLUMN `pic` TO `image`", "ALTER TABLE `email` RENAME COLUMN `email_id` TO `id`", "ALTER TABLE `email` ADD CONSTRAINT `fk_email_user_5b58673d` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE", @@ -839,6 +841,7 @@ def test_migrate(mocker: MockerFixture): 'ALTER TABLE "email" DROP COLUMN "user_id"', 'ALTER TABLE "product" RENAME COLUMN "image" TO "pic"', 'ALTER TABLE "email" RENAME COLUMN "id" TO "email_id"', + 'ALTER TABLE "configs" RENAME TO "config"', 'ALTER TABLE "email" DROP CONSTRAINT "fk_email_user_5b58673d"', 'CREATE INDEX "idx_email_email_4a1a33" ON "email" ("email")', 'CREATE UNIQUE INDEX "uid_product_name_f14935" ON "product" ("name", "type")', @@ -860,6 +863,7 @@ def test_migrate(mocker: MockerFixture): 'ALTER TABLE "config" ALTER COLUMN "status" SET DEFAULT 1', 'ALTER TABLE "email" ADD "user_id" INT NOT NULL', 'ALTER TABLE "email" DROP COLUMN "address"', + 'ALTER TABLE "config" RENAME TO "configs"', 'ALTER TABLE "product" RENAME COLUMN "pic" TO "image"', 'ALTER TABLE "email" RENAME COLUMN "email_id" TO "id"', 'ALTER TABLE "email" ADD CONSTRAINT "fk_email_user_5b58673d" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE',