From daf47f891e33a042b2f4cc37622d593f2c1fb12c Mon Sep 17 00:00:00 2001 From: collerek Date: Tue, 15 Dec 2020 14:11:46 +0100 Subject: [PATCH] fixed in general --- ormar/fields/foreign_key.py | 1 - ormar/models/metaclass.py | 19 +++++++++++++++---- ormar/models/modelproxy.py | 12 +++++++++--- ormar/queryset/join.py | 13 ++++++++++--- ormar/queryset/prefetch_query.py | 16 +++++++++++++--- ormar/relations/relation.py | 5 ++++- ormar/relations/relation_manager.py | 6 +++--- ormar/relations/relation_proxy.py | 19 ++++++++++++++++--- ...efetch_related_multiple_models_relation.py | 7 +------ 9 files changed, 71 insertions(+), 27 deletions(-) diff --git a/ormar/fields/foreign_key.py b/ormar/fields/foreign_key.py index 081ffb5..c188fa4 100644 --- a/ormar/fields/foreign_key.py +++ b/ormar/fields/foreign_key.py @@ -164,7 +164,6 @@ class ForeignKeyField(BaseField): ) -> Optional[Union["Model", List["Model"]]]: if value is None: return None if not cls.virtual else [] - print('expanding', relation_name) constructors = { f"{cls.to.__name__}": cls._register_existing_model, "dict": cls._construct_model_from_dict, diff --git a/ormar/models/metaclass.py b/ormar/models/metaclass.py index b3a38a4..8f84f77 100644 --- a/ormar/models/metaclass.py +++ b/ormar/models/metaclass.py @@ -89,18 +89,28 @@ def register_reverse_model_fields( ) -> None: if issubclass(model_field, ManyToManyField): model.Meta.model_fields[child_model_name] = ManyToMany( - child, through=model_field.through, name=child_model_name, virtual=True, related_name=model_field.name + child, + through=model_field.through, + name=child_model_name, + virtual=True, + related_name=model_field.name, ) # register foreign keys on through model - adjust_through_many_to_many_model(model, child, model_field) + adjust_through_many_to_many_model(model, child, model_field, child_model_name) else: model.Meta.model_fields[child_model_name] = ForeignKey( - child, real_name=child_model_name, virtual=True, related_name=model_field.name + child, + real_name=child_model_name, + virtual=True, + related_name=model_field.name, ) def adjust_through_many_to_many_model( - model: Type["Model"], child: Type["Model"], model_field: Type[ManyToManyField] + model: Type["Model"], + child: Type["Model"], + model_field: Type[ManyToManyField], + child_model_name: str, ) -> None: model_field.through.Meta.model_fields[model.get_name()] = ForeignKey( model, real_name=model.get_name(), ondelete="CASCADE" @@ -148,6 +158,7 @@ def create_and_append_m2m_fk( model.Meta.tablename + "." + model.get_column_alias(model.Meta.pkname), ondelete="CASCADE", onupdate="CASCADE", + related_name=model_field.name, ), ) model_field.through.Meta.columns.append(column) diff --git a/ormar/models/modelproxy.py b/ormar/models/modelproxy.py index 2c3701d..d05ee39 100644 --- a/ormar/models/modelproxy.py +++ b/ormar/models/modelproxy.py @@ -62,11 +62,17 @@ class ModelTableProxy: @staticmethod def get_clause_target_and_filter_column_name( - parent_model: Type["Model"], target_model: Type["Model"], reverse: bool, related: str, + parent_model: Type["Model"], + target_model: Type["Model"], + reverse: bool, + related: str, ) -> Tuple[Type["Model"], str]: if reverse: - field = parent_model.Meta.model_fields[related] - # field = target_model.resolve_relation_field(target_model, parent_model) + field_name = ( + parent_model.Meta.model_fields[related].related_name + or parent_model.get_name() + "s" + ) + field = target_model.Meta.model_fields[field_name] if issubclass(field, ormar.fields.ManyToManyField): sub_field = target_model.resolve_relation_field( field.through, parent_model diff --git a/ormar/queryset/join.py b/ormar/queryset/join.py index fa32fd6..87e7889 100644 --- a/ormar/queryset/join.py +++ b/ormar/queryset/join.py @@ -262,9 +262,16 @@ class SqlJoin: model_cls: Type["Model"], part: str, ) -> Tuple[str, str]: - if join_params.prev_model.Meta.model_fields[part].virtual or is_multi: - to_field = model_cls.resolve_relation_name( - model_cls, join_params.prev_model + if is_multi: + to_field = join_params.prev_model.get_name() + to_key = model_cls.get_column_alias(to_field) + from_key = join_params.prev_model.get_column_alias( + join_params.prev_model.Meta.pkname + ) + elif join_params.prev_model.Meta.model_fields[part].virtual: + to_field = ( + join_params.prev_model.Meta.model_fields[part].related_name + or join_params.prev_model.get_name() + "s" ) to_key = model_cls.get_column_alias(to_field) from_key = join_params.prev_model.get_column_alias( diff --git a/ormar/queryset/prefetch_query.py b/ormar/queryset/prefetch_query.py index f626542..a2d631d 100644 --- a/ormar/queryset/prefetch_query.py +++ b/ormar/queryset/prefetch_query.py @@ -145,7 +145,11 @@ class PrefetchQuery: ) def _get_filter_for_prefetch( - self, parent_model: Type["Model"], target_model: Type["Model"], reverse: bool, related: str, + self, + parent_model: Type["Model"], + target_model: Type["Model"], + reverse: bool, + related: str, ) -> List: ids = self._extract_required_ids( parent_model=parent_model, target_model=target_model, reverse=reverse, @@ -155,7 +159,10 @@ class PrefetchQuery: clause_target, filter_column, ) = parent_model.get_clause_target_and_filter_column_name( - parent_model=parent_model, target_model=target_model, reverse=reverse, related=related + parent_model=parent_model, + target_model=target_model, + reverse=reverse, + related=related, ) qryclause = QueryClause( model_cls=clause_target, select_related=[], filter_clauses=[], @@ -246,7 +253,10 @@ class PrefetchQuery: parent_model = target_model filter_clauses = self._get_filter_for_prefetch( - parent_model=parent_model, target_model=target_field.to, reverse=reverse, related=related + parent_model=parent_model, + target_model=target_field.to, + reverse=reverse, + related=related, ) if not filter_clauses: # related field is empty return diff --git a/ormar/relations/relation.py b/ormar/relations/relation.py index 0b9bb1d..68b8334 100644 --- a/ormar/relations/relation.py +++ b/ormar/relations/relation.py @@ -49,7 +49,10 @@ class Relation: if i not in self._to_remove ] self.related_models = RelationProxy( - relation=self, type_=self._type, field_name=self.field_name, data_=cleaned_data + relation=self, + type_=self._type, + field_name=self.field_name, + data_=cleaned_data, ) relation_name = self._owner.resolve_relation_name(self._owner, self.to) self._owner.__dict__[relation_name] = cleaned_data diff --git a/ormar/relations/relation_manager.py b/ormar/relations/relation_manager.py index 832a46c..12f175d 100644 --- a/ormar/relations/relation_manager.py +++ b/ormar/relations/relation_manager.py @@ -65,17 +65,17 @@ class RelationsManager: relation_name: str, ) -> None: to_field: Type[BaseField] = child.Meta.model_fields[relation_name] - print('comming', child_name, 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 ) - print('adding', parent.get_name(), child.get_name(), child_name) + # print('adding', 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.get_name(), parent.get_name(), child_name) child_relation = child._orm._get(to_name) if child_relation: child_relation.add(parent) diff --git a/ormar/relations/relation_proxy.py b/ormar/relations/relation_proxy.py index 07d09fb..ec83107 100644 --- a/ormar/relations/relation_proxy.py +++ b/ormar/relations/relation_proxy.py @@ -1,4 +1,4 @@ -from typing import Any, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING import ormar from ormar.exceptions import NoMatch, RelationshipInstanceError @@ -12,7 +12,11 @@ if TYPE_CHECKING: # pragma no cover class RelationProxy(list): def __init__( - self, relation: "Relation", type_: "RelationType", field_name: str, data_: Any = None + self, + relation: "Relation", + type_: "RelationType", + field_name: str, + data_: Any = None, ) -> None: super().__init__(data_ or ()) self.relation: "Relation" = relation @@ -20,8 +24,17 @@ class RelationProxy(list): self.field_name = field_name self._owner: "Model" = self.relation.manager.owner self.queryset_proxy = QuerysetProxy(relation=self.relation, type_=type_) + self._related_field_name: Optional[str] = None + + @property + def related_field_name(self) -> str: + if self._related_field_name: + return self._related_field_name owner_field = self._owner.Meta.model_fields[self.field_name] - self.related_field_name = owner_field.related_name or self._owner.get_name() + 's' + self._related_field_name = ( + owner_field.related_name or self._owner.get_name() + "s" + ) + return self._related_field_name def __getattribute__(self, item: str) -> Any: if item in ["count", "clear"]: diff --git a/tests/test_prefetch_related_multiple_models_relation.py b/tests/test_prefetch_related_multiple_models_relation.py index 70b4bd2..5f49a9e 100644 --- a/tests/test_prefetch_related_multiple_models_relation.py +++ b/tests/test_prefetch_related_multiple_models_relation.py @@ -94,11 +94,6 @@ async def test_add_students(): assert user.attending is not None assert len(user.attending) > 0 - query = Session.objects.prefetch_related( - [ - "students", - "teacher", - ] - ) + query = Session.objects.prefetch_related(["students", "teacher",]) sessions = await query.all() assert len(sessions) == 5