WIP skip relation registration on m2m through instance, simplify registering relations part 2

This commit is contained in:
collerek
2021-01-10 12:06:49 +01:00
parent 055c99ba02
commit 4071ff7d11
13 changed files with 114 additions and 120 deletions

View File

@ -13,7 +13,7 @@ if TYPE_CHECKING: # pragma no cover
alias_manager = AliasManager()
def register_relation_on_build(new_model: Type["Model"], field_name: str) -> None:
def register_relation_on_build(field: Type["ForeignKeyField"]) -> None:
"""
Registers ForeignKey relation in alias_manager to set a table_prefix.
Registration include also reverse relation side to be able to join both sides.
@ -22,17 +22,17 @@ def register_relation_on_build(new_model: Type["Model"], field_name: str) -> Non
relations between two Models that needs to have different
aliases for proper sql joins.
:param new_model: constructed model
:type new_model: Model class
:param field_name: name of the related field
:type field_name: str
:param field: relation field
:type field: ForeignKey class
"""
alias_manager.add_relation_type(new_model, field_name)
alias_manager.add_relation_type(
source_model=field.owner,
relation_name=field.name,
reverse_name=field.get_source_related_name(),
)
def register_many_to_many_relation_on_build(
new_model: Type["Model"], field: Type[ManyToManyField], field_name: str
) -> None:
def register_many_to_many_relation_on_build(field: Type[ManyToManyField]) -> None:
"""
Registers connection between through model and both sides of the m2m relation.
Registration include also reverse relation side to be able to join both sides.
@ -43,21 +43,18 @@ def register_many_to_many_relation_on_build(
By default relation name is a model.name.lower().
:param field_name: name of the relation key
:type field_name: str
:param new_model: model on which m2m field is declared
:type new_model: Model class
:param field: relation field
:type field: ManyToManyField class
"""
alias_manager.add_relation_type(
field.through, new_model.get_name(), is_multi=True, reverse_name=field_name
source_model=field.through,
relation_name=field.default_source_field_name(),
reverse_name=field.get_source_related_name(),
)
alias_manager.add_relation_type(
field.through,
field.to.get_name(),
is_multi=True,
reverse_name=field.related_name or new_model.get_name() + "s",
source_model=field.through,
relation_name=field.default_target_field_name(),
reverse_name=field.get_related_name(),
)
@ -126,7 +123,7 @@ def register_reverse_model_fields(model_field: Type["ForeignKeyField"]) -> None:
def register_relation_in_alias_manager(
new_model: Type["Model"], field: Type[ForeignKeyField], field_name: str
field: Type[ForeignKeyField], field_name: str
) -> None:
"""
Registers the relation (and reverse relation) in alias manager.
@ -137,8 +134,6 @@ def register_relation_in_alias_manager(
m2m - register_many_to_many_relation_on_build
fk - register_relation_on_build
:param new_model: model on which relation field is declared
:type new_model: Model class
:param field: relation field
:type field: ForeignKey or ManyToManyField class
:param field_name: name of the relation key
@ -147,13 +142,11 @@ def register_relation_in_alias_manager(
if issubclass(field, ManyToManyField):
if field.has_unresolved_forward_refs():
return
register_many_to_many_relation_on_build(
new_model=new_model, field=field, field_name=field_name
)
register_many_to_many_relation_on_build(field=field)
elif issubclass(field, ForeignKeyField):
if field.has_unresolved_forward_refs():
return
register_relation_on_build(new_model=new_model, field_name=field_name)
register_relation_on_build(field=field)
def verify_related_name_dont_duplicate(

View File

@ -29,10 +29,16 @@ def adjust_through_many_to_many_model(model_field: Type[ManyToManyField]) -> Non
child_name = model_field.default_source_field_name()
model_field.through.Meta.model_fields[parent_name] = ForeignKey(
model_field.to, real_name=parent_name, ondelete="CASCADE"
model_field.to,
real_name=parent_name,
ondelete="CASCADE",
owner=model_field.owner,
)
model_field.through.Meta.model_fields[child_name] = ForeignKey(
model_field.owner, real_name=child_name, ondelete="CASCADE"
model_field.owner,
real_name=child_name,
ondelete="CASCADE",
owner=model_field.owner,
)
create_and_append_m2m_fk(

View File

@ -587,7 +587,9 @@ class ModelMetaclass(pydantic.main.ModelMetaclass):
populate_meta_sqlalchemy_table_if_required(new_model.Meta)
expand_reverse_relationships(new_model)
for field_name, field in new_model.Meta.model_fields.items():
register_relation_in_alias_manager(new_model, field, field_name)
register_relation_in_alias_manager(
field=field, field_name=field_name
)
if new_model.Meta.pkname not in attrs["__annotations__"]:
field_name = new_model.Meta.pkname

View File

@ -15,6 +15,7 @@ from typing import (
Type,
TypeVar,
Union,
cast,
)
try:
@ -143,7 +144,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
k: self._convert_json(
k,
self.Meta.model_fields[k].expand_relationship(
v, self, to_register=False, relation_name=k
v, self, to_register=False,
),
"dumps",
)
@ -172,7 +173,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
# register the columns models after initialization
for related in self.extract_related_names():
self.Meta.model_fields[related].expand_relationship(
new_kwargs.get(related), self, to_register=True, relation_name=related
new_kwargs.get(related), self, to_register=True,
)
def __setattr__(self, name: str, value: Any) -> None: # noqa CCR001
@ -209,7 +210,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
self.set_save_status(False)
elif name in self._orm:
model = self.Meta.model_fields[name].expand_relationship(
value=value, child=self, relation_name=name
value=value, child=self
)
if isinstance(self.__dict__.get(name), list):
# virtual foreign key or many to many
@ -447,13 +448,12 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
fields_to_check = cls.Meta.model_fields.copy()
for field_name, field in fields_to_check.items():
if field.has_unresolved_forward_refs():
field = cast(Type[ForeignKeyField], field)
field.evaluate_forward_ref(globalns=globalns, localns=localns)
field.set_self_reference_flag()
expand_reverse_relationship(model_field=field)
register_relation_in_alias_manager(
cls, # type: ignore
field,
field_name,
field=field, field_name=field_name,
)
update_column_definition(model=cls, field=field)
populate_meta_sqlalchemy_table_if_required(meta=cls.Meta)