intorduce relation flags on basefield and simplify imports

This commit is contained in:
collerek
2021-02-21 17:46:06 +01:00
parent c560245760
commit e697235172
27 changed files with 163 additions and 149 deletions

View File

@ -1,6 +1,7 @@
from typing import (
Any,
Dict,
Generic,
List,
MutableSequence,
Optional,
@ -9,6 +10,7 @@ from typing import (
TYPE_CHECKING,
TypeVar,
Union,
cast,
)
import ormar
@ -16,14 +18,14 @@ from ormar.exceptions import ModelPersistenceError
if TYPE_CHECKING: # pragma no cover
from ormar.relations import Relation
from ormar.models import Model
from ormar.models import Model, T
from ormar.queryset import QuerySet
from ormar import RelationType
T = TypeVar("T", bound=Model)
else:
T = TypeVar("T")
class QuerysetProxy(ormar.QuerySetProtocol):
class QuerysetProxy(Generic[T]):
"""
Exposes QuerySet methods on relations, but also handles creating and removing
of through Models for m2m relations.
@ -47,7 +49,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
self.through_model_name = (
self.related_field.through.get_name()
if self.type_ == ormar.RelationType.MULTIPLE
else None
else ""
)
@property
@ -94,6 +96,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
self._assign_child_to_parent(subchild)
else:
assert isinstance(child, ormar.Model)
child = cast(T, child)
self._assign_child_to_parent(child)
def _clean_items_on_load(self) -> None:
@ -198,7 +201,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
)
return await queryset.delete(**kwargs) # type: ignore
async def first(self, **kwargs: Any) -> "Model":
async def first(self, **kwargs: Any) -> T:
"""
Gets the first row from the db ordered by primary key column ascending.
@ -216,7 +219,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
self._register_related(first)
return first
async def get(self, **kwargs: Any) -> "Model":
async def get(self, **kwargs: Any) -> "T":
"""
Get's the first row from the db meeting the criteria set by kwargs.
@ -240,7 +243,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
self._register_related(get)
return get
async def all(self, **kwargs: Any) -> Sequence[Optional["Model"]]: # noqa: A003
async def all(self, **kwargs: Any) -> Sequence[Optional["T"]]: # noqa: A003
"""
Returns all rows from a database for given model for set filter options.
@ -262,7 +265,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
self._register_related(all_items)
return all_items
async def create(self, **kwargs: Any) -> "Model":
async def create(self, **kwargs: Any) -> "T":
"""
Creates the model instance, saves it in a database and returns the updates model
(with pk populated if not passed and autoincrement is set).
@ -287,7 +290,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
await self.create_through_instance(created, **through_kwargs)
return created
async def get_or_create(self, **kwargs: Any) -> "Model":
async def get_or_create(self, **kwargs: Any) -> "T":
"""
Combination of create and get methods.
@ -305,7 +308,7 @@ class QuerysetProxy(ormar.QuerySetProtocol):
except ormar.NoMatch:
return await self.create(**kwargs)
async def update_or_create(self, **kwargs: Any) -> "Model":
async def update_or_create(self, **kwargs: Any) -> "T":
"""
Updates the model, or in case there is no match in database creates a new one.

View File

@ -1,17 +1,13 @@
from enum import Enum
from typing import List, Optional, Set, TYPE_CHECKING, Type, TypeVar, Union
from typing import List, Optional, Set, TYPE_CHECKING, Type, Union
import ormar # noqa I100
from ormar.exceptions import RelationshipInstanceError # noqa I100
from ormar.fields.foreign_key import ForeignKeyField # noqa I100
from ormar.relations.relation_proxy import RelationProxy
if TYPE_CHECKING: # pragma no cover
from ormar import Model
from ormar.relations import RelationsManager
from ormar.models import NewBaseModel
T = TypeVar("T", bound=Model)
from ormar.models import Model, NewBaseModel, T
class RelationType(Enum):
@ -39,7 +35,7 @@ class Relation:
manager: "RelationsManager",
type_: RelationType,
field_name: str,
to: Type["T"],
to: Type["Model"],
through: Type["T"] = None,
) -> None:
"""
@ -63,10 +59,10 @@ class Relation:
self._owner: "Model" = manager.owner
self._type: RelationType = type_
self._to_remove: Set = set()
self.to: Type["T"] = to
self._through: Optional[Type["T"]] = through
self.to: Type["Model"] = to
self._through = through
self.field_name: str = field_name
self.related_models: Optional[Union[RelationProxy, "T"]] = (
self.related_models: Optional[Union[RelationProxy, "Model"]] = (
RelationProxy(relation=self, type_=type_, field_name=field_name)
if type_ in (RelationType.REVERSE, RelationType.MULTIPLE)
else None
@ -161,7 +157,7 @@ class Relation:
self.related_models.pop(position) # type: ignore
del self._owner.__dict__[relation_name][position]
def get(self) -> Optional[Union[List["T"], "T"]]:
def get(self) -> Optional[Union[List["Model"], "Model"]]:
"""
Return the related model or models from RelationProxy.

View File

@ -1,17 +1,12 @@
from typing import Dict, List, Optional, Sequence, TYPE_CHECKING, Type, TypeVar, Union
from typing import Dict, List, Optional, Sequence, TYPE_CHECKING, Type, Union
from weakref import proxy
from ormar.fields import BaseField, ThroughField
from ormar.fields.foreign_key import ForeignKeyField
from ormar.fields.many_to_many import ManyToManyField
from ormar.relations.relation import Relation, RelationType
from ormar.relations.utils import get_relations_sides_and_names
if TYPE_CHECKING: # pragma no cover
from ormar import Model
from ormar.models import NewBaseModel
T = TypeVar("T", bound=Model)
from ormar.models import NewBaseModel, T, Model
from ormar.fields import ForeignKeyField, BaseField
class RelationsManager:
@ -21,8 +16,8 @@ class RelationsManager:
def __init__(
self,
related_fields: List[Type[ForeignKeyField]] = None,
owner: "NewBaseModel" = None,
related_fields: List[Type["ForeignKeyField"]] = None,
owner: Optional["T"] = None,
) -> None:
self.owner = proxy(owner)
self._related_fields = related_fields or []
@ -31,7 +26,7 @@ class RelationsManager:
for field in self._related_fields:
self._add_relation(field)
def _get_relation_type(self, field: Type[BaseField]) -> RelationType:
def _get_relation_type(self, field: Type["BaseField"]) -> RelationType:
"""
Returns type of the relation declared on a field.
@ -40,13 +35,13 @@ class RelationsManager:
:return: type of the relation defined on field
:rtype: RelationType
"""
if issubclass(field, ManyToManyField):
if field.is_multi:
return RelationType.MULTIPLE
if issubclass(field, ThroughField):
if field.is_through:
return RelationType.THROUGH
return RelationType.PRIMARY if not field.virtual else RelationType.REVERSE
def _add_relation(self, field: Type[BaseField]) -> None:
def _add_relation(self, field: Type["BaseField"]) -> None:
"""
Registers relation in the manager.
Adds Relation instance under field.name.
@ -73,7 +68,7 @@ class RelationsManager:
"""
return item in self._related_names
def get(self, name: str) -> Optional[Union["T", Sequence["T"]]]:
def get(self, name: str) -> Optional[Union["Model", Sequence["Model"]]]:
"""
Returns the related model/models if relation is set.
Actual call is delegated to Relation instance registered under relation name.

View File

@ -27,7 +27,9 @@ class RelationProxy(list):
self.type_: "RelationType" = type_
self.field_name = field_name
self._owner: "Model" = self.relation.manager.owner
self.queryset_proxy = QuerysetProxy(relation=self.relation, type_=type_)
self.queryset_proxy: QuerysetProxy = QuerysetProxy(
relation=self.relation, type_=type_
)
self._related_field_name: Optional[str] = None
@property