Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
- tortoise022
- tortoise023
- tortoise024
# TODO: add dev back when drop python3.8 support
# - tortoisedev
steps:
- name: Start MySQL
run: sudo systemctl start mysql.service
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#### Added
- feat: support command `python -m aerich`. ([#417])
- feat: add --fake to upgrade/downgrade. ([#398])
- Support ignore table by settings `managed=False` in `Meta` class. ([#397])

#### Fixed
- fix: aerich migrate raises tortoise.exceptions.FieldError when `index.INDEX_TYPE` is not empty. ([#415])
Expand All @@ -17,6 +18,7 @@
### Changed
- 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
[#401]: https://github.com/tortoise/aerich/pull/401
[#404]: https://github.com/tortoise/aerich/pull/404
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,16 @@ aerich 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

This project is licensed under the
Expand Down
12 changes: 11 additions & 1 deletion aerich/migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,11 @@ def _handle_m2m_fields(
) -> None:
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_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):
if (option and option[-1] == "nullable") or change[0][0] == "db_constraint":
continue
Expand Down Expand Up @@ -387,6 +391,8 @@ def diff_models(
models_with_rename_field: set[str] = set() # models that trigger the click.prompt

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])
if new_model_str not in old_models:
if upgrade:
Expand All @@ -397,6 +403,8 @@ def diff_models(
pass
else:
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
new_table = cast(str, new_model_describe.get("table"))
old_table = cast(str, old_model_describe.get("table"))
Expand Down Expand Up @@ -593,6 +601,8 @@ def diff_models(
)

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)

@classmethod
Expand Down
15 changes: 6 additions & 9 deletions aerich/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,11 @@ def get_app_connection_name(config, app_name: str) -> str:
get connection name
:param config:
:param app_name:
:return:
:return: the default connection name (Usally it is 'default')
"""
app = config.get("apps").get(app_name)
if not app:
raise BadOptionUsage(
option_name="--app",
message=f'Can\'t get app named "{app_name}"',
)
return app.get("default_connection", "default")
if app := config.get("apps").get(app_name):
return app.get("default_connection", "default")
raise BadOptionUsage(option_name="--app", message=f"Can't get app named {app_name!r}")


def get_app_connection(config, app) -> BaseDBAsyncClient:
Expand Down Expand Up @@ -89,8 +85,9 @@ def get_models_describe(app: str) -> dict:
"""
ret = {}
for model in Tortoise.apps[app].values():
managed = getattr(model.Meta, "managed", None)
describe = model.describe()
ret[describe.get("name")] = describe
ret[describe.get("name")] = dict(describe, managed=managed)
return ret


Expand Down
16 changes: 16 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class Product(Model):
class Meta:
unique_together = (("name", "type"),)
indexes = (("name", "type"),)
managed = True


class Config(Model):
Expand All @@ -118,6 +119,21 @@ class Config(Model):

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):
name = fields.CharField(max_length=50)
37 changes: 37 additions & 0 deletions tests/old_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,40 @@ class Config(Model):

class Meta:
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()