WIP skip relation registration on m2m through instance, simplify registering relations part 2
This commit is contained in:
@ -79,11 +79,7 @@ class AliasManager:
|
||||
return text(f"{name} {alias}_{name}")
|
||||
|
||||
def add_relation_type(
|
||||
self,
|
||||
source_model: Type["Model"],
|
||||
relation_name: str,
|
||||
reverse_name: str = None,
|
||||
is_multi: bool = False,
|
||||
self, source_model: Type["Model"], relation_name: str, reverse_name: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Registers the relations defined in ormar models.
|
||||
@ -104,21 +100,16 @@ class AliasManager:
|
||||
:type relation_name: str
|
||||
:param reverse_name: name of related_name fo given relation for m2m relations
|
||||
:type reverse_name: Optional[str]
|
||||
:param is_multi: flag if relation being registered is a through m2m model
|
||||
:type is_multi: bool
|
||||
:return: none
|
||||
:rtype: None
|
||||
"""
|
||||
parent_key = f"{source_model.get_name()}_{relation_name}"
|
||||
if parent_key not in self._aliases_new:
|
||||
self._aliases_new[parent_key] = get_table_alias()
|
||||
|
||||
to_field = source_model.Meta.model_fields[relation_name]
|
||||
child_model = to_field.to
|
||||
related_name = to_field.related_name
|
||||
if not related_name:
|
||||
related_name = reverse_name if is_multi else source_model.get_name() + "s"
|
||||
|
||||
child_key = f"{child_model.get_name()}_{related_name}"
|
||||
child_key = f"{child_model.get_name()}_{reverse_name}"
|
||||
if child_key not in self._aliases_new:
|
||||
self._aliases_new[child_key] = get_table_alias()
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ from typing import (
|
||||
)
|
||||
|
||||
import ormar
|
||||
from ormar.exceptions import ModelPersistenceError
|
||||
|
||||
if TYPE_CHECKING: # pragma no cover
|
||||
from ormar.relations import Relation
|
||||
@ -106,11 +107,19 @@ class QuerysetProxy(ormar.QuerySetProtocol):
|
||||
:param child: child model instance
|
||||
:type child: Model
|
||||
"""
|
||||
queryset = ormar.QuerySet(model_cls=self.relation.through)
|
||||
model_cls = self.relation.through
|
||||
owner_column = self._owner.get_name()
|
||||
child_column = child.get_name()
|
||||
kwargs = {owner_column: self._owner, child_column: child}
|
||||
await queryset.create(**kwargs)
|
||||
kwargs = {owner_column: self._owner.pk, child_column: child.pk}
|
||||
if child.pk is None:
|
||||
raise ModelPersistenceError(
|
||||
f"You cannot save {child.get_name()} "
|
||||
f"model without primary key set! \n"
|
||||
f"Save the child model first."
|
||||
)
|
||||
expr = model_cls.Meta.table.insert()
|
||||
expr = expr.values(**kwargs)
|
||||
await model_cls.Meta.database.execute(expr)
|
||||
|
||||
async def delete_through_instance(self, child: "T") -> None:
|
||||
"""
|
||||
|
||||
@ -63,7 +63,7 @@ class Relation:
|
||||
self._type: RelationType = type_
|
||||
self._to_remove: Set = set()
|
||||
self.to: Type["T"] = to
|
||||
self.through: Optional[Type["T"]] = through
|
||||
self._through: Optional[Type["T"]] = through
|
||||
self.field_name = field_name
|
||||
self.related_models: Optional[Union[RelationProxy, "T"]] = (
|
||||
RelationProxy(relation=self, type_=type_, field_name=field_name)
|
||||
@ -71,6 +71,12 @@ class Relation:
|
||||
else None
|
||||
)
|
||||
|
||||
@property
|
||||
def through(self) -> Type["T"]:
|
||||
if not self._through: # pragma: no cover
|
||||
raise RelationshipInstanceError("Relation does not have through model!")
|
||||
return self._through
|
||||
|
||||
def _clean_related(self) -> None:
|
||||
"""
|
||||
Removes dead weakrefs from RelationProxy.
|
||||
|
||||
@ -101,13 +101,7 @@ class RelationsManager:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def add(
|
||||
parent: "Model",
|
||||
child: "Model",
|
||||
child_name: str,
|
||||
virtual: bool,
|
||||
relation_name: str,
|
||||
) -> None:
|
||||
def add(parent: "Model", child: "Model", field: Type["ForeignKeyField"],) -> None:
|
||||
"""
|
||||
Adds relation on both sides -> meaning on both child and parent models.
|
||||
One side of the relation is always weakref proxy to avoid circular refs.
|
||||
@ -120,25 +114,19 @@ class RelationsManager:
|
||||
:type parent: Model
|
||||
:param child: child model to register
|
||||
:type child: Model
|
||||
:param child_name: potential child name used if related name is not set
|
||||
:type child_name: str
|
||||
:param virtual:
|
||||
:type virtual: bool
|
||||
:param relation_name: name of the relation
|
||||
:type relation_name: str
|
||||
:param field: field with relation definition
|
||||
:type field: ForeignKeyField
|
||||
"""
|
||||
to_field: Type[BaseField] = child.Meta.model_fields[relation_name]
|
||||
# print('comming', child_name, relation_name)
|
||||
(parent, child, child_name, to_name,) = get_relations_sides_and_names(
|
||||
to_field, parent, child, child_name, virtual, relation_name
|
||||
field, parent, child
|
||||
)
|
||||
|
||||
# print('adding', parent.get_name(), child.get_name(), child_name)
|
||||
# print('adding parent', parent.get_name(), child.get_name(), child_name)
|
||||
parent_relation = parent._orm._get(child_name)
|
||||
if parent_relation:
|
||||
parent_relation.add(child) # type: ignore
|
||||
|
||||
# print('adding', child.get_name(), parent.get_name(), child_name)
|
||||
# print('adding child', child.get_name(), parent.get_name(), to_name)
|
||||
child_relation = child._orm._get(to_name)
|
||||
if child_relation:
|
||||
child_relation.add(parent)
|
||||
|
||||
@ -1,48 +1,33 @@
|
||||
from typing import TYPE_CHECKING, Tuple, Type
|
||||
from weakref import proxy
|
||||
|
||||
from ormar.fields import BaseField
|
||||
from ormar.fields.many_to_many import ManyToManyField
|
||||
from ormar.fields.foreign_key import ForeignKeyField
|
||||
|
||||
if TYPE_CHECKING: # pragma no cover
|
||||
from ormar import Model
|
||||
|
||||
|
||||
def get_relations_sides_and_names(
|
||||
to_field: Type[BaseField],
|
||||
parent: "Model",
|
||||
child: "Model",
|
||||
child_name: str,
|
||||
virtual: bool,
|
||||
relation_name: str,
|
||||
to_field: Type[ForeignKeyField], parent: "Model", child: "Model",
|
||||
) -> Tuple["Model", "Model", str, str]:
|
||||
"""
|
||||
Determines the names of child and parent relations names, as well as
|
||||
changes one of the sides of the relation into weakref.proxy to model.
|
||||
|
||||
:param to_field: field with relation definition
|
||||
:type to_field: BaseField
|
||||
:type to_field: ForeignKeyField
|
||||
:param parent: parent model
|
||||
:type parent: Model
|
||||
:param child: child model
|
||||
:type child: Model
|
||||
:param child_name: name of the child
|
||||
:type child_name: str
|
||||
:param virtual: flag if relation is virtual
|
||||
:type virtual: bool
|
||||
:param relation_name:
|
||||
:type relation_name:
|
||||
:return: parent, child, child_name, to_name
|
||||
:rtype: Tuple["Model", "Model", str, str]
|
||||
"""
|
||||
to_name = to_field.name
|
||||
if issubclass(to_field, ManyToManyField):
|
||||
child_name = to_field.related_name or child.get_name() + "s"
|
||||
child = proxy(child)
|
||||
elif virtual:
|
||||
child_name, to_name = to_name, child_name or child.get_name()
|
||||
child_name = to_field.get_related_name()
|
||||
if to_field.virtual:
|
||||
child_name, to_name = to_name, child_name
|
||||
child, parent = parent, proxy(child)
|
||||
else:
|
||||
child_name = child_name or child.get_name() + "s"
|
||||
child = proxy(child)
|
||||
return parent, child, child_name, to_name
|
||||
|
||||
Reference in New Issue
Block a user