WIP skip relation registration on m2m through instance, simplify registering relations part 2
This commit is contained in:
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user