Base class for all Tortoise ORM Models.
| 718 | |
| 719 | |
| 720 | class Model(metaclass=ModelMeta): |
| 721 | """ |
| 722 | Base class for all Tortoise ORM Models. |
| 723 | """ |
| 724 | |
| 725 | # I don' like this here, but it makes auto completion and static analysis much happier |
| 726 | _meta = MetaInfo(None) # type: ignore |
| 727 | _listeners: dict[Signals, dict[type[MODEL], list[Callable]]] = { # type: ignore |
| 728 | Signals.pre_save: {}, |
| 729 | Signals.post_save: {}, |
| 730 | Signals.pre_delete: {}, |
| 731 | Signals.post_delete: {}, |
| 732 | } |
| 733 | |
| 734 | def __init__(self, **kwargs: Any) -> None: |
| 735 | # self._meta is a very common attribute lookup, lets cache it. |
| 736 | meta = self._meta |
| 737 | self._partial = False |
| 738 | self._saved_in_db = False |
| 739 | self._custom_generated_pk = False |
| 740 | self._await_when_save: dict[str, Callable[[], Awaitable[Any]]] = {} |
| 741 | |
| 742 | # Assign defaults for missing fields |
| 743 | for key in meta.fields.difference(self._set_kwargs(kwargs)): |
| 744 | field_object = meta.fields_map[key] |
| 745 | field_default = field_object.default |
| 746 | if inspect.iscoroutinefunction(field_default): |
| 747 | self._await_when_save[key] = field_default |
| 748 | elif callable(field_default): |
| 749 | setattr(self, key, field_default()) |
| 750 | else: |
| 751 | default = field_object.default |
| 752 | if default is not None: |
| 753 | if isinstance(default, (int, float, str, bool, bytes)): |
| 754 | setattr(self, key, default) |
| 755 | else: |
| 756 | setattr(self, key, deepcopy(default)) |
| 757 | elif field_object.has_db_default(): |
| 758 | setattr(self, key, field_object.get_db_default_value()) |
| 759 | else: |
| 760 | setattr(self, key, None) |
| 761 | |
| 762 | def __setattr__(self, key, value) -> None: |
| 763 | # set field value override async default function |
| 764 | if hasattr(self, "_await_when_save"): |
| 765 | self._await_when_save.pop(key, None) |
| 766 | if key in self._meta.fk_fields or key in self._meta.o2o_fields: |
| 767 | self._validate_relation_type(key, value) |
| 768 | super().__setattr__(key, value) |
| 769 | |
| 770 | def _set_kwargs(self, kwargs: dict) -> set[str]: |
| 771 | meta = self._meta |
| 772 | |
| 773 | # Assign values and do type conversions |
| 774 | passed_fields = {*kwargs.keys()} | meta.fetch_fields |
| 775 | |
| 776 | for key, value in kwargs.items(): |
| 777 | if key in meta.fk_fields or key in meta.o2o_fields: |
nothing calls this directly
no test coverage detected
searching dependent graphs…