add select_all

This commit is contained in:
collerek
2021-03-21 15:22:40 +01:00
parent 859ed5d1fc
commit 74beaa31b7
8 changed files with 182 additions and 36 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ class UndefinedType: # pragma no cover
Undefined = UndefinedType()
__version__ = "0.9.9"
__version__ = "0.10.0"
__all__ = [
"Integer",
"BigInteger",
+2 -3
View File
@@ -14,7 +14,7 @@ from typing import (
TYPE_CHECKING,
Type,
Union,
cast, no_type_check,
cast,
)
try:
@@ -47,7 +47,6 @@ from ormar.relations.relation_manager import RelationsManager
if TYPE_CHECKING: # pragma no cover
from ormar.models import Model
from ormar.signals import SignalEmitter
from ormar.queryset import QuerySet
IntStr = Union[int, str]
DictStrAny = Dict[str, Any]
@@ -232,7 +231,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
super().__setattr__(name, value)
self.set_save_status(False)
def __getattribute__(self, item: str): # noqa: CCR001
def __getattribute__(self, item: str) -> Any: # noqa: CCR001
"""
Because we need to overwrite getting the attribute by ormar instead of pydantic
as well as returning related models and not the value stored on the model the
+31 -5
View File
@@ -1,13 +1,15 @@
from typing import (
Any,
Dict,
Generic, List,
Generic,
List,
Optional,
Sequence,
Set,
TYPE_CHECKING,
Type,
TypeVar, Union,
TypeVar,
Union,
cast,
)
@@ -17,7 +19,7 @@ from sqlalchemy import bindparam
import ormar # noqa I100
from ormar import MultipleMatches, NoMatch
from ormar.exceptions import ModelError, ModelPersistenceError, QueryDefinitionError
from ormar.exceptions import ModelPersistenceError, QueryDefinitionError
from ormar.queryset import FilterQuery, SelectAction
from ormar.queryset.actions.order_action import OrderAction
from ormar.queryset.clause import FilterGroup, QueryClause
@@ -28,7 +30,6 @@ if TYPE_CHECKING: # pragma no cover
from ormar import Model
from ormar.models import T
from ormar.models.metaclass import ModelMeta
from ormar.relations.querysetproxy import QuerysetProxy
from ormar.models.excludable import ExcludableItems
else:
T = TypeVar("T", bound="Model")
@@ -65,7 +66,6 @@ class QuerySet(Generic[T]):
self.order_bys = order_bys or []
self.limit_sql_raw = limit_raw_sql
@property
def model_meta(self) -> "ModelMeta":
"""
@@ -369,6 +369,32 @@ class QuerySet(Generic[T]):
related = sorted(list(set(list(self._select_related) + related)))
return self.rebuild_self(select_related=related,)
def select_all(self, follow: bool = False) -> "QuerySet[T]":
"""
By default adds only directly related models.
If follow=True is set it adds also related models of related models.
To not get stuck in an infinite loop as related models also keep a relation
to parent model visited models set is kept.
That way already visited models that are nested are loaded, but the load do not
follow them inside. So Model A -> Model B -> Model C -> Model A -> Model X
will load second Model A but will never follow into Model X.
Nested relations of those kind need to be loaded manually.
:param follow: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
:type follow: bool
:return: reloaded Model
:rtype: Model
"""
relations = list(self.model.extract_related_names())
if follow:
relations = self.model._iterate_related_models()
return self.rebuild_self(select_related=relations,)
def prefetch_related(self, related: Union[List, str]) -> "QuerySet[T]":
"""
Allows to prefetch related models during query - but opposite to
+76 -23
View File
@@ -2,17 +2,19 @@ from _weakref import CallableProxyType
from typing import ( # noqa: I100, I201
Any,
Dict,
Generic, List,
Generic,
List,
MutableSequence,
Optional,
Sequence,
Set,
TYPE_CHECKING,
Type, TypeVar, Union,
Type,
TypeVar,
Union,
cast,
)
import ormar # noqa: I100, I202
from ormar.exceptions import ModelPersistenceError, QueryDefinitionError
@@ -35,10 +37,11 @@ class QuerysetProxy(Generic[T]):
relation: "Relation"
def __init__(
self, relation: "Relation",
to: Type["T"],
type_: "RelationType",
qryset: "QuerySet[T]" = None
self,
relation: "Relation",
to: Type["T"],
type_: "RelationType",
qryset: "QuerySet[T]" = None,
) -> None:
self.relation: Relation = relation
self._queryset: Optional["QuerySet[T]"] = qryset
@@ -88,9 +91,7 @@ class QuerysetProxy(Generic[T]):
rel_name = self.relation.field_name
setattr(owner, rel_name, child)
def _register_related(
self, child: Union["T", Sequence[Optional["T"]]]
) -> None:
def _register_related(self, child: Union["T", Sequence[Optional["T"]]]) -> None:
"""
Registers child/ children in parents RelationManager.
@@ -418,7 +419,9 @@ class QuerysetProxy(Generic[T]):
model = await self.queryset.get(pk=kwargs[pk_name])
return await model.update(**kwargs)
def filter(self, *args: Any, **kwargs: Any) -> "QuerysetProxy[T]": # noqa: A003, A001
def filter( # noqa: A003, A001
self, *args: Any, **kwargs: Any
) -> "QuerysetProxy[T]":
"""
Allows you to filter by any `Model` attribute/field
as well as to fetch instances, with a filter across an FK relationship.
@@ -449,9 +452,13 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.filter(*args, **kwargs)
return self.__class__(relation=self.relation, type_=self.type_, to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def exclude(self, *args: Any, **kwargs: Any) -> "QuerysetProxy[T]": # noqa: A003, A001
def exclude(
self, *args: Any, **kwargs: Any
) -> "QuerysetProxy[T]": # noqa: A003, A001
"""
Works exactly the same as filter and all modifiers (suffixes) are the same,
but returns a *not* condition.
@@ -473,7 +480,35 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.exclude(*args, **kwargs)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def select_all(self, follow: bool = False) -> "QuerysetProxy[T]":
"""
By default adds only directly related models.
If follow=True is set it adds also related models of related models.
To not get stuck in an infinite loop as related models also keep a relation
to parent model visited models set is kept.
That way already visited models that are nested are loaded, but the load do not
follow them inside. So Model A -> Model B -> Model C -> Model A -> Model X
will load second Model A but will never follow into Model X.
Nested relations of those kind need to be loaded manually.
:param follow: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
:type follow: bool
:return: reloaded Model
:rtype: Model
"""
queryset = self.queryset.select_all(follow=follow)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def select_related(self, related: Union[List, str]) -> "QuerysetProxy[T]":
"""
@@ -495,7 +530,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.select_related(related)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def prefetch_related(self, related: Union[List, str]) -> "QuerysetProxy[T]":
"""
@@ -518,7 +555,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.prefetch_related(related)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def paginate(self, page: int, page_size: int = 20) -> "QuerysetProxy[T]":
"""
@@ -535,7 +574,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerySet
"""
queryset = self.queryset.paginate(page=page, page_size=page_size)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def limit(self, limit_count: int) -> "QuerysetProxy[T]":
"""
@@ -549,7 +590,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.limit(limit_count)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def offset(self, offset: int) -> "QuerysetProxy[T]":
"""
@@ -563,7 +606,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.offset(offset)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def fields(self, columns: Union[List, str, Set, Dict]) -> "QuerysetProxy[T]":
"""
@@ -611,9 +656,13 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.fields(columns)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def exclude_fields(self, columns: Union[List, str, Set, Dict]) -> "QuerysetProxy[T]":
def exclude_fields(
self, columns: Union[List, str, Set, Dict]
) -> "QuerysetProxy[T]":
"""
With `exclude_fields()` you can select subset of model columns that will
be excluded to limit the data load.
@@ -643,7 +692,9 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.exclude_fields(columns=columns)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
def order_by(self, columns: Union[List, str]) -> "QuerysetProxy[T]":
"""
@@ -680,4 +731,6 @@ class QuerysetProxy(Generic[T]):
:rtype: QuerysetProxy
"""
queryset = self.queryset.order_by(columns)
return self.__class__(relation=self.relation, type_=self.type_,to=self.to, qryset=queryset)
return self.__class__(
relation=self.relation, type_=self.type_, to=self.to, qryset=queryset
)
+11 -3
View File
@@ -1,6 +1,15 @@
from enum import Enum
from typing import Generic, List, Optional, Set, TYPE_CHECKING, Type, TypeVar, Union, \
cast
from typing import (
Generic,
List,
Optional,
Set,
TYPE_CHECKING,
Type,
TypeVar,
Union,
cast,
)
import ormar # noqa I100
from ormar.exceptions import RelationshipInstanceError # noqa I100
@@ -9,7 +18,6 @@ from ormar.relations.relation_proxy import RelationProxy
if TYPE_CHECKING: # pragma no cover
from ormar.relations import RelationsManager
from ormar.models import Model, NewBaseModel, T
from ormar.relations.relation_proxy import RelationProxy
else:
T = TypeVar("T", bound="Model")
+1 -1
View File
@@ -52,7 +52,7 @@ class RelationProxy(Generic[T], list):
return self._related_field_name
def __getitem__(self, item) -> "T": # type: ignore
def __getitem__(self, item: Any) -> "T": # type: ignore
return super().__getitem__(item)
def __getattribute__(self, item: str) -> Any: