diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b776c7..f6690dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### 0.5.2 - Fix rename field on the field add. (#134) +- Fix postgres field type change error. (#135) ### 0.5.1 diff --git a/README.md b/README.md index acb68bc..9cf823a 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,7 @@ ## Introduction Aerich is a database migrations tool for Tortoise-ORM, which is like alembic for SQLAlchemy, or like Django ORM with -it\'s own migrations solution. - -~~**Important: You can only use absolutely import in your `models.py` to make `aerich` work.**~~ - -From version `v0.5.0`, there is no such limitation now. +it\'s own migration solution. ## Install @@ -97,8 +93,8 @@ Success create app migrate location ./migrations/models Success generate schema for app "models" ``` -If your Tortoise-ORM app is not the default `models`, you must specify the correct app via `--app`, e.g. `aerich ---app other_models init-db`. +If your Tortoise-ORM app is not the default `models`, you must specify the correct app via `--app`, +e.g. `aerich --app other_models init-db`. ### Update models and make migrate @@ -193,8 +189,7 @@ Inspect a specified table in the default app and redirect to `models.py`: aerich inspectdb -t user > models.py ``` -Note that this command is limited and cannot infer some fields, such as `IntEnumField`, `ForeignKeyField`, and -others. +Note that this command is limited and cannot infer some fields, such as `IntEnumField`, `ForeignKeyField`, and others. ### Multiple databases @@ -213,12 +208,6 @@ tortoise_orm = { You only need to specify `aerich.models` in one app, and must specify `--app` when running `aerich migrate` and so on. -## Support this project - -| AliPay | WeChatPay | PayPal | -| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | -| | | [PayPal](https://www.paypal.me/long2ice) to my account long2ice. | - ## License This project is licensed under the diff --git a/aerich/ddl/postgres/__init__.py b/aerich/ddl/postgres/__init__.py index 415489d..d5282cd 100644 --- a/aerich/ddl/postgres/__init__.py +++ b/aerich/ddl/postgres/__init__.py @@ -12,7 +12,9 @@ class PostgresDDL(BaseDDL): _ADD_INDEX_TEMPLATE = 'CREATE {unique}INDEX "{index_name}" ON "{table_name}" ({column_names})' _DROP_INDEX_TEMPLATE = 'DROP INDEX "{index_name}"' _ALTER_NULL_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" {set_drop} NOT NULL' - _MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" TYPE {datatype}' + _MODIFY_COLUMN_TEMPLATE = ( + 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" TYPE {datatype}{using}' + ) _SET_COMMENT_TEMPLATE = 'COMMENT ON COLUMN "{table_name}"."{column}" IS {comment}' _DROP_FK_TEMPLATE = 'ALTER TABLE "{table_name}" DROP CONSTRAINT "{fk_name}"' @@ -27,10 +29,13 @@ class PostgresDDL(BaseDDL): def modify_column(self, model: "Type[Model]", field_describe: dict, is_pk: bool = False): db_table = model._meta.db_table db_field_types = field_describe.get("db_field_types") + db_column = field_describe.get("db_column") + datatype = db_field_types.get(self.DIALECT) or db_field_types.get("") return self._MODIFY_COLUMN_TEMPLATE.format( table_name=db_table, - column=field_describe.get("db_column"), - datatype=db_field_types.get(self.DIALECT) or db_field_types.get(""), + column=db_column, + datatype=datatype, + using=f' USING "{db_column}"::{datatype}', ) def set_comment(self, model: "Type[Model]", field_describe: dict): diff --git a/aerich/migrate.py b/aerich/migrate.py index 95700cd..8f842fe 100644 --- a/aerich/migrate.py +++ b/aerich/migrate.py @@ -392,6 +392,9 @@ class Migrate: elif option == "default": # change column default cls._add_operator(cls._alter_default(model, new_data_field), upgrade) + elif option == "unique": + # because indexed include it + pass else: # modify column cls._add_operator( diff --git a/images/alipay.jpeg b/images/alipay.jpeg deleted file mode 100644 index c2b63b4..0000000 Binary files a/images/alipay.jpeg and /dev/null differ diff --git a/images/wechatpay.jpeg b/images/wechatpay.jpeg deleted file mode 100644 index c2618e4..0000000 Binary files a/images/wechatpay.jpeg and /dev/null differ diff --git a/tests/test_ddl.py b/tests/test_ddl.py index ea5d0ec..c5f1c6e 100644 --- a/tests/test_ddl.py +++ b/tests/test_ddl.py @@ -76,7 +76,10 @@ def test_modify_column(): if isinstance(Migrate.ddl, MysqlDDL): assert ret0 == "ALTER TABLE `category` MODIFY COLUMN `name` VARCHAR(200)" elif isinstance(Migrate.ddl, PostgresDDL): - assert ret0 == 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200)' + assert ( + ret0 + == 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200) USING "name"::VARCHAR(200)' + ) if isinstance(Migrate.ddl, MysqlDDL): assert ( @@ -84,7 +87,9 @@ def test_modify_column(): == "ALTER TABLE `user` MODIFY COLUMN `is_active` BOOL NOT NULL COMMENT 'Is Active' DEFAULT 1" ) elif isinstance(Migrate.ddl, PostgresDDL): - assert ret1 == 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL' + assert ( + ret1 == 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL USING "is_active"::BOOL' + ) def test_alter_column_default(): diff --git a/tests/test_migrate.py b/tests/test_migrate.py index ad90a85..54d806d 100644 --- a/tests/test_migrate.py +++ b/tests/test_migrate.py @@ -768,7 +768,7 @@ def test_migrate(mocker: MockerFixture): - alter default: Config.status - rename column: Product.image -> Product.pic """ - mocker.patch("click.prompt", side_effect=(False, True)) + mocker.patch("click.prompt", side_effect=(True,)) models_describe = get_models_describe("models") Migrate.app = "models" @@ -798,7 +798,6 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `product` ALTER COLUMN `view_num` SET DEFAULT 0", "ALTER TABLE `user` DROP COLUMN `avatar`", "ALTER TABLE `user` MODIFY COLUMN `password` VARCHAR(100) NOT NULL", - "ALTER TABLE `user` MODIFY COLUMN `username` VARCHAR(20) NOT NULL", "CREATE TABLE IF NOT EXISTS `newmodel` (\n `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,\n `name` VARCHAR(50) NOT NULL\n) CHARACTER SET utf8mb4;", "ALTER TABLE `user` ADD UNIQUE INDEX `uid_user_usernam_9987ab` (`username`)", "CREATE TABLE `email_user` (`email_id` INT NOT NULL REFERENCES `email` (`email_id`) ON DELETE CASCADE,`user_id` INT NOT NULL REFERENCES `user` (`id`) ON DELETE CASCADE) CHARACTER SET utf8mb4", @@ -823,7 +822,6 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `user` ADD `avatar` VARCHAR(200) NOT NULL DEFAULT ''", "ALTER TABLE `user` DROP INDEX `idx_user_usernam_9987ab`", "ALTER TABLE `user` MODIFY COLUMN `password` VARCHAR(200) NOT NULL", - "ALTER TABLE `user` MODIFY COLUMN `username` VARCHAR(20) NOT NULL", "DROP TABLE IF EXISTS `email_user`", "DROP TABLE IF EXISTS `newmodel`", ] @@ -832,8 +830,8 @@ def test_migrate(mocker: MockerFixture): elif isinstance(Migrate.ddl, PostgresDDL): assert sorted(Migrate.upgrade_operators) == sorted( [ - 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200)', - 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(100)', + 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200) USING "name"::VARCHAR(200)', + 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(100) USING "slug"::VARCHAR(100)', 'ALTER TABLE "config" ADD "user_id" INT NOT NULL', 'ALTER TABLE "config" ADD CONSTRAINT "fk_config_user_17daa970" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE', 'ALTER TABLE "config" ALTER COLUMN "status" DROP DEFAULT', @@ -843,11 +841,10 @@ def test_migrate(mocker: MockerFixture): 'ALTER TABLE "email" RENAME COLUMN "id" TO "email_id"', 'ALTER TABLE "email" DROP CONSTRAINT "fk_email_user_5b58673d"', 'CREATE INDEX "idx_email_email_4a1a33" ON "email" ("email")', - 'ALTER TABLE "user" ALTER COLUMN "username" TYPE VARCHAR(20)', 'CREATE UNIQUE INDEX "uid_product_name_f14935" ON "product" ("name", "type")', 'ALTER TABLE "product" ALTER COLUMN "view_num" SET DEFAULT 0', 'ALTER TABLE "user" DROP COLUMN "avatar"', - 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(100)', + 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(100) USING "password"::VARCHAR(100)', 'CREATE TABLE IF NOT EXISTS "newmodel" (\n "id" SERIAL NOT NULL PRIMARY KEY,\n "name" VARCHAR(50) NOT NULL\n);\nCOMMENT ON COLUMN "config"."user_id" IS \'User\';', 'CREATE UNIQUE INDEX "uid_user_usernam_9987ab" ON "user" ("username")', 'CREATE TABLE "email_user" ("email_id" INT NOT NULL REFERENCES "email" ("email_id") ON DELETE CASCADE,"user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE)', @@ -855,10 +852,9 @@ def test_migrate(mocker: MockerFixture): ) assert sorted(Migrate.downgrade_operators) == sorted( [ - 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200)', - 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(200)', - 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(200)', - 'ALTER TABLE "user" ALTER COLUMN "username" TYPE VARCHAR(20)', + 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200) USING "name"::VARCHAR(200)', + 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(200) USING "slug"::VARCHAR(200)', + 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(200) USING "password"::VARCHAR(200)', 'ALTER TABLE "config" DROP COLUMN "user_id"', 'ALTER TABLE "config" DROP CONSTRAINT "fk_config_user_17daa970"', 'ALTER TABLE "config" ALTER COLUMN "status" SET DEFAULT 1',