feat: support skip table migration by set managed=False (#397)
This commit is contained in:
parent
41df464e8b
commit
91adf9334e
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -26,6 +26,8 @@ jobs:
|
|||||||
- tortoise022
|
- tortoise022
|
||||||
- tortoise023
|
- tortoise023
|
||||||
- tortoise024
|
- tortoise024
|
||||||
|
# TODO: add dev back when drop python3.8 support
|
||||||
|
# - tortoisedev
|
||||||
steps:
|
steps:
|
||||||
- name: Start MySQL
|
- name: Start MySQL
|
||||||
run: sudo systemctl start mysql.service
|
run: sudo systemctl start mysql.service
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#### Added
|
#### Added
|
||||||
- feat: support command `python -m aerich`. ([#417])
|
- feat: support command `python -m aerich`. ([#417])
|
||||||
- feat: add --fake to upgrade/downgrade. ([#398])
|
- feat: add --fake to upgrade/downgrade. ([#398])
|
||||||
|
- Support ignore table by settings `managed=False` in `Meta` class. ([#397])
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
- fix: aerich migrate raises tortoise.exceptions.FieldError when `index.INDEX_TYPE` is not empty. ([#415])
|
- fix: aerich migrate raises tortoise.exceptions.FieldError when `index.INDEX_TYPE` is not empty. ([#415])
|
||||||
@ -17,6 +18,7 @@
|
|||||||
### Changed
|
### Changed
|
||||||
- Refactored version management to use `importlib.metadata.version(__package__)` instead of hardcoded version string ([#412])
|
- Refactored version management to use `importlib.metadata.version(__package__)` instead of hardcoded version string ([#412])
|
||||||
|
|
||||||
|
[#397]: https://github.com/tortoise/aerich/pull/397
|
||||||
[#398]: https://github.com/tortoise/aerich/pull/398
|
[#398]: https://github.com/tortoise/aerich/pull/398
|
||||||
[#401]: https://github.com/tortoise/aerich/pull/401
|
[#401]: https://github.com/tortoise/aerich/pull/401
|
||||||
[#404]: https://github.com/tortoise/aerich/pull/404
|
[#404]: https://github.com/tortoise/aerich/pull/404
|
||||||
|
10
README.md
10
README.md
@ -295,6 +295,16 @@ aerich downgrade --fake -v 2
|
|||||||
aerich --app models downgrade --fake -v 2
|
aerich --app models downgrade --fake -v 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Ignore tables
|
||||||
|
|
||||||
|
You can tell aerich to ignore table by setting `managed=False` in the `Meta` class, e.g.:
|
||||||
|
```py
|
||||||
|
class MyModel(Model):
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
```
|
||||||
|
**Note** `managed=False` does not recognized by `tortoise-orm` and `aerich init-db`, it is only for `aerich migrate`.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the
|
This project is licensed under the
|
||||||
|
@ -264,7 +264,11 @@ class Migrate:
|
|||||||
) -> None:
|
) -> None:
|
||||||
old_m2m_fields = cast("list[dict]", old_model_describe.get("m2m_fields", []))
|
old_m2m_fields = cast("list[dict]", old_model_describe.get("m2m_fields", []))
|
||||||
new_m2m_fields = cast("list[dict]", new_model_describe.get("m2m_fields", []))
|
new_m2m_fields = cast("list[dict]", new_model_describe.get("m2m_fields", []))
|
||||||
new_tables: dict[str, dict] = {field["table"]: field for field in new_models.values()}
|
new_tables: dict[str, dict] = {
|
||||||
|
field["table"]: field
|
||||||
|
for field in new_models.values()
|
||||||
|
if field.get("managed") is not False
|
||||||
|
}
|
||||||
for action, option, change in get_dict_diff_by_key(old_m2m_fields, new_m2m_fields):
|
for action, option, change in get_dict_diff_by_key(old_m2m_fields, new_m2m_fields):
|
||||||
if (option and option[-1] == "nullable") or change[0][0] == "db_constraint":
|
if (option and option[-1] == "nullable") or change[0][0] == "db_constraint":
|
||||||
continue
|
continue
|
||||||
@ -387,6 +391,8 @@ class Migrate:
|
|||||||
models_with_rename_field: set[str] = set() # models that trigger the click.prompt
|
models_with_rename_field: set[str] = set() # models that trigger the click.prompt
|
||||||
|
|
||||||
for new_model_str, new_model_describe in new_models.items():
|
for new_model_str, new_model_describe in new_models.items():
|
||||||
|
if upgrade and new_model_describe.get("managed") is False:
|
||||||
|
continue
|
||||||
model = cls._get_model(new_model_describe["name"].split(".")[1])
|
model = cls._get_model(new_model_describe["name"].split(".")[1])
|
||||||
if new_model_str not in old_models:
|
if new_model_str not in old_models:
|
||||||
if upgrade:
|
if upgrade:
|
||||||
@ -397,6 +403,8 @@ class Migrate:
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
old_model_describe = cast(dict, old_models.get(new_model_str))
|
old_model_describe = cast(dict, old_models.get(new_model_str))
|
||||||
|
if not upgrade and old_model_describe.get("managed") is False:
|
||||||
|
continue
|
||||||
# rename table
|
# rename table
|
||||||
new_table = cast(str, new_model_describe.get("table"))
|
new_table = cast(str, new_model_describe.get("table"))
|
||||||
old_table = cast(str, old_model_describe.get("table"))
|
old_table = cast(str, old_model_describe.get("table"))
|
||||||
@ -593,6 +601,8 @@ class Migrate:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for old_model in old_models.keys() - new_models.keys():
|
for old_model in old_models.keys() - new_models.keys():
|
||||||
|
if not upgrade and old_models[old_model].get("managed") is False:
|
||||||
|
continue
|
||||||
cls._add_operator(cls.drop_model(old_models[old_model]["table"]), upgrade)
|
cls._add_operator(cls.drop_model(old_models[old_model]["table"]), upgrade)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -34,15 +34,11 @@ def get_app_connection_name(config, app_name: str) -> str:
|
|||||||
get connection name
|
get connection name
|
||||||
:param config:
|
:param config:
|
||||||
:param app_name:
|
:param app_name:
|
||||||
:return:
|
:return: the default connection name (Usally it is 'default')
|
||||||
"""
|
"""
|
||||||
app = config.get("apps").get(app_name)
|
if app := config.get("apps").get(app_name):
|
||||||
if not app:
|
return app.get("default_connection", "default")
|
||||||
raise BadOptionUsage(
|
raise BadOptionUsage(option_name="--app", message=f"Can't get app named {app_name!r}")
|
||||||
option_name="--app",
|
|
||||||
message=f'Can\'t get app named "{app_name}"',
|
|
||||||
)
|
|
||||||
return app.get("default_connection", "default")
|
|
||||||
|
|
||||||
|
|
||||||
def get_app_connection(config, app) -> BaseDBAsyncClient:
|
def get_app_connection(config, app) -> BaseDBAsyncClient:
|
||||||
@ -89,8 +85,9 @@ def get_models_describe(app: str) -> dict:
|
|||||||
"""
|
"""
|
||||||
ret = {}
|
ret = {}
|
||||||
for model in Tortoise.apps[app].values():
|
for model in Tortoise.apps[app].values():
|
||||||
|
managed = getattr(model.Meta, "managed", None)
|
||||||
describe = model.describe()
|
describe = model.describe()
|
||||||
ret[describe.get("name")] = describe
|
ret[describe.get("name")] = dict(describe, managed=managed)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ class Product(Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (("name", "type"),)
|
unique_together = (("name", "type"),)
|
||||||
indexes = (("name", "type"),)
|
indexes = (("name", "type"),)
|
||||||
|
managed = True
|
||||||
|
|
||||||
|
|
||||||
class Config(Model):
|
class Config(Model):
|
||||||
@ -118,6 +119,21 @@ class Config(Model):
|
|||||||
|
|
||||||
email: fields.OneToOneRelation[Email]
|
email: fields.OneToOneRelation[Email]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = True
|
||||||
|
|
||||||
|
|
||||||
|
class DontManageMe(Model):
|
||||||
|
name = fields.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
|
||||||
|
class Ignore(Model):
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
|
||||||
class NewModel(Model):
|
class NewModel(Model):
|
||||||
name = fields.CharField(max_length=50)
|
name = fields.CharField(max_length=50)
|
||||||
|
@ -89,3 +89,40 @@ class Config(Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
table = "configs"
|
table = "configs"
|
||||||
|
|
||||||
|
|
||||||
|
class DontManageMe(Model):
|
||||||
|
name = fields.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = "dont_manage"
|
||||||
|
|
||||||
|
|
||||||
|
class Ignore(Model):
|
||||||
|
name = fields.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = True
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Generate a python file for the old_models_describe"""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from tortoise import run_async
|
||||||
|
from tortoise.contrib.test import init_memory_sqlite
|
||||||
|
|
||||||
|
from aerich.utils import get_models_describe
|
||||||
|
|
||||||
|
@init_memory_sqlite
|
||||||
|
async def run() -> None:
|
||||||
|
old_models_describe = get_models_describe("models")
|
||||||
|
p = Path("old_models_describe.py")
|
||||||
|
p.write_text(f"{old_models_describe = }", encoding="utf-8")
|
||||||
|
print(f"Write value to {p}\nYou can reformat it by `ruff format {p}`")
|
||||||
|
|
||||||
|
run_async(run())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user