wip with m2m fields
This commit is contained in:
@ -12,6 +12,20 @@ class Excludable:
|
|||||||
include: Set = field(default_factory=set)
|
include: Set = field(default_factory=set)
|
||||||
exclude: Set = field(default_factory=set)
|
exclude: Set = field(default_factory=set)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def include_all(self):
|
||||||
|
return ... in self.include
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exclude_all(self):
|
||||||
|
return ... in self.exclude
|
||||||
|
|
||||||
|
def get_copy(self) -> "Excludable":
|
||||||
|
_copy = self.__class__()
|
||||||
|
_copy.include = {x for x in self.include}
|
||||||
|
_copy.exclude = {x for x in self.exclude}
|
||||||
|
return _copy
|
||||||
|
|
||||||
def set_values(self, value: Set, is_exclude: bool) -> None:
|
def set_values(self, value: Set, is_exclude: bool) -> None:
|
||||||
prop = "exclude" if is_exclude else "include"
|
prop = "exclude" if is_exclude else "include"
|
||||||
if ... in getattr(self, prop) or ... in value:
|
if ... in getattr(self, prop) or ... in value:
|
||||||
@ -38,15 +52,22 @@ class ExcludableItems:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.items: Dict[str, Excludable] = dict()
|
self.items: Dict[str, Excludable] = dict()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_excludable(cls, other: "ExcludableItems") -> "ExcludableItems":
|
||||||
|
new_excludable = cls()
|
||||||
|
for key, value in other.items.items():
|
||||||
|
new_excludable.items[key] = value.get_copy()
|
||||||
|
return new_excludable
|
||||||
|
|
||||||
def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
|
def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
|
||||||
key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
|
key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
|
||||||
return self.items.get(key, Excludable())
|
return self.items.get(key, Excludable())
|
||||||
|
|
||||||
def build(
|
def build(
|
||||||
self,
|
self,
|
||||||
items: Union[List[str], str, Tuple[str], Set[str], Dict],
|
items: Union[List[str], str, Tuple[str], Set[str], Dict],
|
||||||
model_cls: Type["Model"],
|
model_cls: Type["Model"],
|
||||||
is_exclude: bool = False,
|
is_exclude: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
if isinstance(items, str):
|
if isinstance(items, str):
|
||||||
@ -75,7 +96,7 @@ class ExcludableItems:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _set_excludes(
|
def _set_excludes(
|
||||||
self, items: Set, model_name: str, is_exclude: bool, alias: str = ""
|
self, items: Set, model_name: str, is_exclude: bool, alias: str = ""
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
key = f"{alias + '_' if alias else ''}{model_name}"
|
key = f"{alias + '_' if alias else ''}{model_name}"
|
||||||
@ -86,13 +107,13 @@ class ExcludableItems:
|
|||||||
self.items[key] = excludable
|
self.items[key] = excludable
|
||||||
|
|
||||||
def _traverse_dict( # noqa: CFQ002
|
def _traverse_dict( # noqa: CFQ002
|
||||||
self,
|
self,
|
||||||
values: Dict,
|
values: Dict,
|
||||||
source_model: Type["Model"],
|
source_model: Type["Model"],
|
||||||
model_cls: Type["Model"],
|
model_cls: Type["Model"],
|
||||||
is_exclude: bool,
|
is_exclude: bool,
|
||||||
related_items: List = None,
|
related_items: List = None,
|
||||||
alias: str = "",
|
alias: str = "",
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self_fields = set()
|
self_fields = set()
|
||||||
@ -144,7 +165,7 @@ class ExcludableItems:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _traverse_list(
|
def _traverse_list(
|
||||||
self, values: Set[str], model_cls: Type["Model"], is_exclude: bool
|
self, values: Set[str], model_cls: Type["Model"], is_exclude: bool
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
# here we have only nested related keys
|
# here we have only nested related keys
|
||||||
|
|||||||
@ -9,9 +9,10 @@ from typing import (
|
|||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union, cast,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.models.mixins.relation_mixin import RelationMixin
|
from ormar.models.mixins.relation_mixin import RelationMixin
|
||||||
from ormar.queryset.utils import translate_list_to_dict, update
|
from ormar.queryset.utils import translate_list_to_dict, update
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_child(
|
def get_child(
|
||||||
items: Union[Set, Dict, None], key: str = None
|
items: Union[Set, Dict, None], key: str = None
|
||||||
) -> Union[Set, Dict, None]:
|
) -> Union[Set, Dict, None]:
|
||||||
"""
|
"""
|
||||||
Used to get nested dictionaries keys if they exists otherwise returns
|
Used to get nested dictionaries keys if they exists otherwise returns
|
||||||
@ -53,7 +54,7 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_excluded(
|
def get_excluded(
|
||||||
exclude: Union[Set, Dict, None], key: str = None
|
exclude: Union[Set, Dict, None], key: str = None
|
||||||
) -> Union[Set, Dict, None]:
|
) -> Union[Set, Dict, None]:
|
||||||
"""
|
"""
|
||||||
Proxy to ExcludableMixin.get_child for exclusions.
|
Proxy to ExcludableMixin.get_child for exclusions.
|
||||||
@ -69,7 +70,7 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_included(
|
def get_included(
|
||||||
include: Union[Set, Dict, None], key: str = None
|
include: Union[Set, Dict, None], key: str = None
|
||||||
) -> Union[Set, Dict, None]:
|
) -> Union[Set, Dict, None]:
|
||||||
"""
|
"""
|
||||||
Proxy to ExcludableMixin.get_child for inclusions.
|
Proxy to ExcludableMixin.get_child for inclusions.
|
||||||
@ -131,9 +132,9 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _populate_pk_column(
|
def _populate_pk_column(
|
||||||
model: Union[Type["Model"], Type["ModelRow"]],
|
model: Union[Type["Model"], Type["ModelRow"]],
|
||||||
columns: List[str],
|
columns: List[str],
|
||||||
use_alias: bool = False,
|
use_alias: bool = False,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Adds primary key column/alias (depends on use_alias flag) to list of
|
Adds primary key column/alias (depends on use_alias flag) to list of
|
||||||
@ -159,12 +160,13 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def own_table_columns(
|
def own_table_columns(
|
||||||
cls,
|
cls,
|
||||||
model: Union[Type["Model"], Type["ModelRow"]],
|
model: Union[Type["Model"], Type["ModelRow"]],
|
||||||
fields: Optional[Union[Set, Dict]],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Set, Dict]],
|
alias: str = '',
|
||||||
use_alias: bool = False,
|
use_alias: bool = False,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
# TODO update docstring
|
||||||
"""
|
"""
|
||||||
Returns list of aliases or field names for given model.
|
Returns list of aliases or field names for given model.
|
||||||
Aliases/names switch is use_alias flag.
|
Aliases/names switch is use_alias flag.
|
||||||
@ -176,15 +178,12 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
:param model: model on columns are selected
|
:param model: model on columns are selected
|
||||||
:type model: Type["Model"]
|
:type model: Type["Model"]
|
||||||
:param fields: set/dict of fields to include
|
|
||||||
:type fields: Optional[Union[Set, Dict]]
|
|
||||||
:param exclude_fields: set/dict of fields to exclude
|
|
||||||
:type exclude_fields: Optional[Union[Set, Dict]]
|
|
||||||
:param use_alias: flag if aliases or field names should be used
|
:param use_alias: flag if aliases or field names should be used
|
||||||
:type use_alias: bool
|
:type use_alias: bool
|
||||||
:return: list of column field names or aliases
|
:return: list of column field names or aliases
|
||||||
:rtype: List[str]
|
:rtype: List[str]
|
||||||
"""
|
"""
|
||||||
|
model_excludable = excludable.get(model_cls=model, alias=alias)
|
||||||
columns = [
|
columns = [
|
||||||
model.get_column_name_from_alias(col.name) if not use_alias else col.name
|
model.get_column_name_from_alias(col.name) if not use_alias else col.name
|
||||||
for col in model.Meta.table.columns
|
for col in model.Meta.table.columns
|
||||||
@ -193,17 +192,17 @@ class ExcludableMixin(RelationMixin):
|
|||||||
model.get_column_name_from_alias(col.name)
|
model.get_column_name_from_alias(col.name)
|
||||||
for col in model.Meta.table.columns
|
for col in model.Meta.table.columns
|
||||||
]
|
]
|
||||||
if fields:
|
if model_excludable.include:
|
||||||
columns = [
|
columns = [
|
||||||
col
|
col
|
||||||
for col, name in zip(columns, field_names)
|
for col, name in zip(columns, field_names)
|
||||||
if model.is_included(fields, name)
|
if model_excludable.is_included(name)
|
||||||
]
|
]
|
||||||
if exclude_fields:
|
if model_excludable.exclude:
|
||||||
columns = [
|
columns = [
|
||||||
col
|
col
|
||||||
for col, name in zip(columns, field_names)
|
for col, name in zip(columns, field_names)
|
||||||
if not model.is_excluded(exclude_fields, name)
|
if not model_excludable.is_excluded(name)
|
||||||
]
|
]
|
||||||
|
|
||||||
# always has to return pk column for ormar to work
|
# always has to return pk column for ormar to work
|
||||||
@ -215,9 +214,9 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _update_excluded_with_related_not_required(
|
def _update_excluded_with_related_not_required(
|
||||||
cls,
|
cls,
|
||||||
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None],
|
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None],
|
||||||
nested: bool = False,
|
nested: bool = False,
|
||||||
) -> Union[Set, Dict]:
|
) -> Union[Set, Dict]:
|
||||||
"""
|
"""
|
||||||
Used during generation of the dict().
|
Used during generation of the dict().
|
||||||
@ -245,9 +244,9 @@ class ExcludableMixin(RelationMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_names_to_exclude(
|
def get_names_to_exclude(
|
||||||
cls,
|
cls,
|
||||||
fields: Optional[Union[Dict, Set]] = None,
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Dict, Set]] = None,
|
alias: str
|
||||||
) -> Set:
|
) -> Set:
|
||||||
"""
|
"""
|
||||||
Returns a set of models field names that should be explicitly excluded
|
Returns a set of models field names that should be explicitly excluded
|
||||||
@ -259,33 +258,27 @@ class ExcludableMixin(RelationMixin):
|
|||||||
Used in parsing data from database rows that construct Models by initializing
|
Used in parsing data from database rows that construct Models by initializing
|
||||||
them with dicts constructed from those db rows.
|
them with dicts constructed from those db rows.
|
||||||
|
|
||||||
:param fields: set/dict of fields to include
|
:param alias: alias of current relation
|
||||||
:type fields: Optional[Union[Set, Dict]]
|
:type alias: str
|
||||||
:param exclude_fields: set/dict of fields to exclude
|
:param excludable: structure of fields to include and exclude
|
||||||
:type exclude_fields: Optional[Union[Set, Dict]]
|
:type excludable: ExcludableItems
|
||||||
:return: set of field names that should be excluded
|
:return: set of field names that should be excluded
|
||||||
:rtype: Set
|
:rtype: Set
|
||||||
"""
|
"""
|
||||||
|
model = cast(Type["Model"], cls)
|
||||||
|
model_excludable = excludable.get(model_cls=model, alias=alias)
|
||||||
fields_names = cls.extract_db_own_fields()
|
fields_names = cls.extract_db_own_fields()
|
||||||
if fields and fields is not Ellipsis:
|
if model_excludable.include and model_excludable.include_all:
|
||||||
fields_to_keep = {name for name in fields if name in fields_names}
|
fields_to_keep = model_excludable.include.intersection(fields_names)
|
||||||
else:
|
else:
|
||||||
fields_to_keep = fields_names
|
fields_to_keep = fields_names
|
||||||
|
|
||||||
fields_to_exclude = fields_names - fields_to_keep
|
fields_to_exclude = fields_names - fields_to_keep
|
||||||
|
|
||||||
if isinstance(exclude_fields, Set):
|
if model_excludable.exclude:
|
||||||
fields_to_exclude = fields_to_exclude.union(
|
fields_to_exclude = fields_to_exclude.union(
|
||||||
{name for name in exclude_fields if name in fields_names}
|
model_excludable.exclude.intersection(fields_names)
|
||||||
)
|
)
|
||||||
elif isinstance(exclude_fields, Dict):
|
|
||||||
new_to_exclude = {
|
|
||||||
name
|
|
||||||
for name in exclude_fields
|
|
||||||
if name in fields_names and exclude_fields[name] is Ellipsis
|
|
||||||
}
|
|
||||||
fields_to_exclude = fields_to_exclude.union(new_to_exclude)
|
|
||||||
|
|
||||||
fields_to_exclude = fields_to_exclude - {cls.Meta.pkname}
|
fields_to_exclude = fields_to_exclude - {cls.Meta.pkname}
|
||||||
|
|
||||||
return fields_to_exclude
|
return fields_to_exclude
|
||||||
|
|||||||
@ -14,6 +14,7 @@ from typing import (
|
|||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from ormar.models import NewBaseModel # noqa: I202
|
from ormar.models import NewBaseModel # noqa: I202
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.models.helpers.models import group_related_list
|
from ormar.models.helpers.models import group_related_list
|
||||||
|
|
||||||
|
|
||||||
@ -33,8 +34,7 @@ class ModelRow(NewBaseModel):
|
|||||||
select_related: List = None,
|
select_related: List = None,
|
||||||
related_models: Any = None,
|
related_models: Any = None,
|
||||||
related_field: Type["ForeignKeyField"] = None,
|
related_field: Type["ForeignKeyField"] = None,
|
||||||
fields: Optional[Union[Dict, Set]] = None,
|
excludable: ExcludableItems = None,
|
||||||
exclude_fields: Optional[Union[Dict, Set]] = None,
|
|
||||||
current_relation_str: str = "",
|
current_relation_str: str = "",
|
||||||
) -> Optional[T]:
|
) -> Optional[T]:
|
||||||
"""
|
"""
|
||||||
@ -50,6 +50,8 @@ class ModelRow(NewBaseModel):
|
|||||||
where rows are populated in a different way as they do not have
|
where rows are populated in a different way as they do not have
|
||||||
nested models in result.
|
nested models in result.
|
||||||
|
|
||||||
|
:param excludable: structure of fields to include and exclude
|
||||||
|
:type excludable: ExcludableItems
|
||||||
:param current_relation_str: name of the relation field
|
:param current_relation_str: name of the relation field
|
||||||
:type current_relation_str: str
|
:type current_relation_str: str
|
||||||
:param source_model: model on which relation was defined
|
:param source_model: model on which relation was defined
|
||||||
@ -62,12 +64,6 @@ class ModelRow(NewBaseModel):
|
|||||||
:type related_models: Union[List, Dict]
|
:type related_models: Union[List, Dict]
|
||||||
:param related_field: field with relation declaration
|
:param related_field: field with relation declaration
|
||||||
:type related_field: Type[ForeignKeyField]
|
:type related_field: Type[ForeignKeyField]
|
||||||
:param fields: fields and related model fields to include
|
|
||||||
if provided only those are included
|
|
||||||
:type fields: Optional[Union[Dict, Set]]
|
|
||||||
:param exclude_fields: fields and related model fields to exclude
|
|
||||||
excludes the fields even if they are provided in fields
|
|
||||||
:type exclude_fields: Optional[Union[Dict, Set]]
|
|
||||||
:return: returns model if model is populated from database
|
:return: returns model if model is populated from database
|
||||||
:rtype: Optional[Model]
|
:rtype: Optional[Model]
|
||||||
"""
|
"""
|
||||||
@ -75,6 +71,7 @@ class ModelRow(NewBaseModel):
|
|||||||
select_related = select_related or []
|
select_related = select_related or []
|
||||||
related_models = related_models or []
|
related_models = related_models or []
|
||||||
table_prefix = ""
|
table_prefix = ""
|
||||||
|
excludable = excludable or ExcludableItems()
|
||||||
|
|
||||||
if select_related:
|
if select_related:
|
||||||
source_model = cast(Type[T], cls)
|
source_model = cast(Type[T], cls)
|
||||||
@ -87,12 +84,11 @@ class ModelRow(NewBaseModel):
|
|||||||
relation_field=related_field,
|
relation_field=related_field,
|
||||||
)
|
)
|
||||||
|
|
||||||
item = cls.populate_nested_models_from_row(
|
item = cls._populate_nested_models_from_row(
|
||||||
item=item,
|
item=item,
|
||||||
row=row,
|
row=row,
|
||||||
related_models=related_models,
|
related_models=related_models,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
current_relation_str=current_relation_str,
|
current_relation_str=current_relation_str,
|
||||||
source_model=source_model,
|
source_model=source_model,
|
||||||
)
|
)
|
||||||
@ -100,28 +96,26 @@ class ModelRow(NewBaseModel):
|
|||||||
item=item,
|
item=item,
|
||||||
row=row,
|
row=row,
|
||||||
table_prefix=table_prefix,
|
table_prefix=table_prefix,
|
||||||
fields=fields,
|
excludable=excludable
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
instance: Optional[T] = None
|
instance: Optional[T] = None
|
||||||
if item.get(cls.Meta.pkname, None) is not None:
|
if item.get(cls.Meta.pkname, None) is not None:
|
||||||
item["__excluded__"] = cls.get_names_to_exclude(
|
item["__excluded__"] = cls.get_names_to_exclude(
|
||||||
fields=fields, exclude_fields=exclude_fields
|
excludable=excludable, alias=table_prefix
|
||||||
)
|
)
|
||||||
instance = cast(T, cls(**item))
|
instance = cast(T, cls(**item))
|
||||||
instance.set_save_status(True)
|
instance.set_save_status(True)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def populate_nested_models_from_row( # noqa: CFQ002
|
def _populate_nested_models_from_row( # noqa: CFQ002
|
||||||
cls,
|
cls,
|
||||||
item: dict,
|
item: dict,
|
||||||
row: sqlalchemy.engine.ResultProxy,
|
row: sqlalchemy.engine.ResultProxy,
|
||||||
source_model: Type[T],
|
source_model: Type[T],
|
||||||
related_models: Any,
|
related_models: Any,
|
||||||
fields: Optional[Union[Dict, Set]] = None,
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Dict, Set]] = None,
|
|
||||||
current_relation_str: str = None,
|
current_relation_str: str = None,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""
|
"""
|
||||||
@ -134,6 +128,8 @@ class ModelRow(NewBaseModel):
|
|||||||
Recurrently calls from_row method on nested instances and create nested
|
Recurrently calls from_row method on nested instances and create nested
|
||||||
instances. In the end those instances are added to the final model dictionary.
|
instances. In the end those instances are added to the final model dictionary.
|
||||||
|
|
||||||
|
:param excludable: structure of fields to include and exclude
|
||||||
|
:type excludable: ExcludableItems
|
||||||
:param source_model: source model from which relation started
|
:param source_model: source model from which relation started
|
||||||
:type source_model: Type[Model]
|
:type source_model: Type[Model]
|
||||||
:param current_relation_str: joined related parts into one string
|
:param current_relation_str: joined related parts into one string
|
||||||
@ -144,12 +140,6 @@ class ModelRow(NewBaseModel):
|
|||||||
:type row: sqlalchemy.engine.result.ResultProxy
|
:type row: sqlalchemy.engine.result.ResultProxy
|
||||||
:param related_models: list or dict of related models
|
:param related_models: list or dict of related models
|
||||||
:type related_models: Union[Dict, List]
|
:type related_models: Union[Dict, List]
|
||||||
:param fields: fields and related model fields to include -
|
|
||||||
if provided only those are included
|
|
||||||
:type fields: Optional[Union[Dict, Set]]
|
|
||||||
:param exclude_fields: fields and related model fields to exclude
|
|
||||||
excludes the fields even if they are provided in fields
|
|
||||||
:type exclude_fields: Optional[Union[Dict, Set]]
|
|
||||||
:return: dictionary with keys corresponding to model fields names
|
:return: dictionary with keys corresponding to model fields names
|
||||||
and values are database values
|
and values are database values
|
||||||
:rtype: Dict
|
:rtype: Dict
|
||||||
@ -163,8 +153,6 @@ class ModelRow(NewBaseModel):
|
|||||||
)
|
)
|
||||||
field = cls.Meta.model_fields[related]
|
field = cls.Meta.model_fields[related]
|
||||||
field = cast(Type["ForeignKeyField"], field)
|
field = cast(Type["ForeignKeyField"], field)
|
||||||
fields = cls.get_included(fields, related)
|
|
||||||
exclude_fields = cls.get_excluded(exclude_fields, related)
|
|
||||||
model_cls = field.to
|
model_cls = field.to
|
||||||
|
|
||||||
remainder = None
|
remainder = None
|
||||||
@ -174,8 +162,7 @@ class ModelRow(NewBaseModel):
|
|||||||
row,
|
row,
|
||||||
related_models=remainder,
|
related_models=remainder,
|
||||||
related_field=field,
|
related_field=field,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
current_relation_str=relation_str,
|
current_relation_str=relation_str,
|
||||||
source_model=source_model,
|
source_model=source_model,
|
||||||
)
|
)
|
||||||
@ -188,8 +175,7 @@ class ModelRow(NewBaseModel):
|
|||||||
row=row,
|
row=row,
|
||||||
related=related,
|
related=related,
|
||||||
through_name=through_name,
|
through_name=through_name,
|
||||||
fields=fields,
|
excludable=excludable
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
)
|
)
|
||||||
item[through_name] = through_child
|
item[through_name] = through_child
|
||||||
setattr(child, through_name, through_child)
|
setattr(child, through_name, through_child)
|
||||||
@ -203,35 +189,29 @@ class ModelRow(NewBaseModel):
|
|||||||
row: sqlalchemy.engine.ResultProxy,
|
row: sqlalchemy.engine.ResultProxy,
|
||||||
through_name: str,
|
through_name: str,
|
||||||
related: str,
|
related: str,
|
||||||
fields: Optional[Union[Dict, Set]] = None,
|
excludable: ExcludableItems
|
||||||
exclude_fields: Optional[Union[Dict, Set]] = None,
|
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
# TODO: fix excludes and includes
|
# TODO: fix excludes and includes and docstring
|
||||||
fields = cls.get_included(fields, through_name)
|
|
||||||
# exclude_fields = cls.get_excluded(exclude_fields, through_name)
|
|
||||||
model_cls = cls.Meta.model_fields[through_name].to
|
model_cls = cls.Meta.model_fields[through_name].to
|
||||||
exclude_fields = model_cls.extract_related_names()
|
|
||||||
table_prefix = cls.Meta.alias_manager.resolve_relation_alias(
|
table_prefix = cls.Meta.alias_manager.resolve_relation_alias(
|
||||||
from_model=cls, relation_name=related
|
from_model=cls, relation_name=related
|
||||||
)
|
)
|
||||||
child = model_cls.extract_prefixed_table_columns(
|
child = model_cls.extract_prefixed_table_columns(
|
||||||
item={},
|
item={},
|
||||||
row=row,
|
row=row,
|
||||||
table_prefix=table_prefix,
|
excludable=excludable,
|
||||||
fields=fields,
|
table_prefix=table_prefix
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
)
|
)
|
||||||
return child
|
return child
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extract_prefixed_table_columns( # noqa CCR001
|
def extract_prefixed_table_columns(
|
||||||
cls,
|
cls,
|
||||||
item: dict,
|
item: dict,
|
||||||
row: sqlalchemy.engine.result.ResultProxy,
|
row: sqlalchemy.engine.result.ResultProxy,
|
||||||
table_prefix: str,
|
table_prefix: str,
|
||||||
fields: Optional[Union[Dict, Set]] = None,
|
excludable: ExcludableItems
|
||||||
exclude_fields: Optional[Union[Dict, Set]] = None,
|
) -> Dict:
|
||||||
) -> dict:
|
|
||||||
"""
|
"""
|
||||||
Extracts own fields from raw sql result, using a given prefix.
|
Extracts own fields from raw sql result, using a given prefix.
|
||||||
Prefix changes depending on the table's position in a join.
|
Prefix changes depending on the table's position in a join.
|
||||||
@ -244,6 +224,8 @@ class ModelRow(NewBaseModel):
|
|||||||
|
|
||||||
Used in Model.from_row and PrefetchQuery._populate_rows methods.
|
Used in Model.from_row and PrefetchQuery._populate_rows methods.
|
||||||
|
|
||||||
|
:param excludable: structure of fields to include and exclude
|
||||||
|
:type excludable: ExcludableItems
|
||||||
:param item: dictionary of already populated nested models, otherwise empty dict
|
:param item: dictionary of already populated nested models, otherwise empty dict
|
||||||
:type item: Dict
|
:type item: Dict
|
||||||
:param row: raw result row from the database
|
:param row: raw result row from the database
|
||||||
@ -252,12 +234,6 @@ class ModelRow(NewBaseModel):
|
|||||||
each pair of tables have own prefix (two of them depending on direction) -
|
each pair of tables have own prefix (two of them depending on direction) -
|
||||||
used in joins to allow multiple joins to the same table.
|
used in joins to allow multiple joins to the same table.
|
||||||
:type table_prefix: str
|
:type table_prefix: str
|
||||||
:param fields: fields and related model fields to include -
|
|
||||||
if provided only those are included
|
|
||||||
:type fields: Optional[Union[Dict, Set]]
|
|
||||||
:param exclude_fields: fields and related model fields to exclude
|
|
||||||
excludes the fields even if they are provided in fields
|
|
||||||
:type exclude_fields: Optional[Union[Dict, Set]]
|
|
||||||
:return: dictionary with keys corresponding to model fields names
|
:return: dictionary with keys corresponding to model fields names
|
||||||
and values are database values
|
and values are database values
|
||||||
:rtype: Dict
|
:rtype: Dict
|
||||||
@ -267,8 +243,8 @@ class ModelRow(NewBaseModel):
|
|||||||
|
|
||||||
selected_columns = cls.own_table_columns(
|
selected_columns = cls.own_table_columns(
|
||||||
model=cls,
|
model=cls,
|
||||||
fields=fields or {},
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields or {},
|
alias=table_prefix,
|
||||||
use_alias=False,
|
use_alias=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ from sqlalchemy import text
|
|||||||
|
|
||||||
import ormar # noqa I100
|
import ormar # noqa I100
|
||||||
from ormar.exceptions import RelationshipInstanceError
|
from ormar.exceptions import RelationshipInstanceError
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.relations import AliasManager
|
from ormar.relations import AliasManager
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma no cover
|
if TYPE_CHECKING: # pragma no cover
|
||||||
@ -29,8 +30,7 @@ class SqlJoin:
|
|||||||
used_aliases: List,
|
used_aliases: List,
|
||||||
select_from: sqlalchemy.sql.select,
|
select_from: sqlalchemy.sql.select,
|
||||||
columns: List[sqlalchemy.Column],
|
columns: List[sqlalchemy.Column],
|
||||||
fields: Optional[Union[Set, Dict]],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Set, Dict]],
|
|
||||||
order_columns: Optional[List["OrderAction"]],
|
order_columns: Optional[List["OrderAction"]],
|
||||||
sorted_orders: OrderedDict,
|
sorted_orders: OrderedDict,
|
||||||
main_model: Type["Model"],
|
main_model: Type["Model"],
|
||||||
@ -44,8 +44,7 @@ class SqlJoin:
|
|||||||
self.related_models = related_models or []
|
self.related_models = related_models or []
|
||||||
self.select_from = select_from
|
self.select_from = select_from
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
self.fields = fields
|
self.excludable=excludable
|
||||||
self.exclude_fields = exclude_fields
|
|
||||||
self.order_columns = order_columns
|
self.order_columns = order_columns
|
||||||
self.sorted_orders = sorted_orders
|
self.sorted_orders = sorted_orders
|
||||||
self.main_model = main_model
|
self.main_model = main_model
|
||||||
@ -200,10 +199,7 @@ class SqlJoin:
|
|||||||
used_aliases=self.used_aliases,
|
used_aliases=self.used_aliases,
|
||||||
select_from=self.select_from,
|
select_from=self.select_from,
|
||||||
columns=self.columns,
|
columns=self.columns,
|
||||||
fields=self.main_model.get_excluded(self.fields, related_name),
|
excludable=self.excludable,
|
||||||
exclude_fields=self.main_model.get_excluded(
|
|
||||||
self.exclude_fields, related_name
|
|
||||||
),
|
|
||||||
order_columns=self.order_columns,
|
order_columns=self.order_columns,
|
||||||
sorted_orders=self.sorted_orders,
|
sorted_orders=self.sorted_orders,
|
||||||
main_model=self.next_model,
|
main_model=self.next_model,
|
||||||
@ -303,8 +299,8 @@ class SqlJoin:
|
|||||||
# TODO: fix fields and exclusions for through model?
|
# TODO: fix fields and exclusions for through model?
|
||||||
self_related_fields = self.next_model.own_table_columns(
|
self_related_fields = self.next_model.own_table_columns(
|
||||||
model=self.next_model,
|
model=self.next_model,
|
||||||
fields=self.fields,
|
excludable=self.excludable,
|
||||||
exclude_fields=self.exclude_fields,
|
alias=self.next_alias,
|
||||||
use_alias=True,
|
use_alias=True,
|
||||||
)
|
)
|
||||||
self.columns.extend(
|
self.columns.extend(
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from typing import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
import ormar
|
import ormar
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.queryset.clause import QueryClause
|
from ormar.queryset.clause import QueryClause
|
||||||
from ormar.queryset.query import Query
|
from ormar.queryset.query import Query
|
||||||
from ormar.queryset.utils import extract_models_to_dict_of_lists, translate_list_to_dict
|
from ormar.queryset.utils import extract_models_to_dict_of_lists, translate_list_to_dict
|
||||||
@ -24,7 +25,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|||||||
|
|
||||||
|
|
||||||
def add_relation_field_to_fields(
|
def add_relation_field_to_fields(
|
||||||
fields: Union[Set[Any], Dict[Any, Any], None], related_field_name: str
|
fields: Union[Set[Any], Dict[Any, Any], None], related_field_name: str
|
||||||
) -> Union[Set[Any], Dict[Any, Any], None]:
|
) -> Union[Set[Any], Dict[Any, Any], None]:
|
||||||
"""
|
"""
|
||||||
Adds related field into fields to include as otherwise it would be skipped.
|
Adds related field into fields to include as otherwise it would be skipped.
|
||||||
@ -73,12 +74,12 @@ def sort_models(models: List["Model"], orders_by: Dict) -> List["Model"]:
|
|||||||
|
|
||||||
|
|
||||||
def set_children_on_model( # noqa: CCR001
|
def set_children_on_model( # noqa: CCR001
|
||||||
model: "Model",
|
model: "Model",
|
||||||
related: str,
|
related: str,
|
||||||
children: Dict,
|
children: Dict,
|
||||||
model_id: int,
|
model_id: int,
|
||||||
models: Dict,
|
models: Dict,
|
||||||
orders_by: Dict,
|
orders_by: Dict,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Extract ids of child models by given relation id key value.
|
Extract ids of child models by given relation id key value.
|
||||||
@ -123,21 +124,19 @@ class PrefetchQuery:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__( # noqa: CFQ002
|
def __init__( # noqa: CFQ002
|
||||||
self,
|
self,
|
||||||
model_cls: Type["Model"],
|
model_cls: Type["Model"],
|
||||||
fields: Optional[Union[Dict, Set]],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Dict, Set]],
|
prefetch_related: List,
|
||||||
prefetch_related: List,
|
select_related: List,
|
||||||
select_related: List,
|
orders_by: List["OrderAction"],
|
||||||
orders_by: List["OrderAction"],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
self.model = model_cls
|
self.model = model_cls
|
||||||
self.database = self.model.Meta.database
|
self.database = self.model.Meta.database
|
||||||
self._prefetch_related = prefetch_related
|
self._prefetch_related = prefetch_related
|
||||||
self._select_related = select_related
|
self._select_related = select_related
|
||||||
self._exclude_columns = exclude_fields
|
self.excludable = excludable
|
||||||
self._columns = fields
|
|
||||||
self.already_extracted: Dict = dict()
|
self.already_extracted: Dict = dict()
|
||||||
self.models: Dict = {}
|
self.models: Dict = {}
|
||||||
self.select_dict = translate_list_to_dict(self._select_related)
|
self.select_dict = translate_list_to_dict(self._select_related)
|
||||||
@ -148,7 +147,7 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def prefetch_related(
|
async def prefetch_related(
|
||||||
self, models: Sequence["Model"], rows: List
|
self, models: Sequence["Model"], rows: List
|
||||||
) -> Sequence["Model"]:
|
) -> Sequence["Model"]:
|
||||||
"""
|
"""
|
||||||
Main entry point for prefetch_query.
|
Main entry point for prefetch_query.
|
||||||
@ -173,7 +172,7 @@ class PrefetchQuery:
|
|||||||
return await self._prefetch_related_models(models=models, rows=rows)
|
return await self._prefetch_related_models(models=models, rows=rows)
|
||||||
|
|
||||||
def _extract_ids_from_raw_data(
|
def _extract_ids_from_raw_data(
|
||||||
self, parent_model: Type["Model"], column_name: str
|
self, parent_model: Type["Model"], column_name: str
|
||||||
) -> Set:
|
) -> Set:
|
||||||
"""
|
"""
|
||||||
Iterates over raw rows and extract id values of relation columns by using
|
Iterates over raw rows and extract id values of relation columns by using
|
||||||
@ -196,7 +195,7 @@ class PrefetchQuery:
|
|||||||
return list_of_ids
|
return list_of_ids
|
||||||
|
|
||||||
def _extract_ids_from_preloaded_models(
|
def _extract_ids_from_preloaded_models(
|
||||||
self, parent_model: Type["Model"], column_name: str
|
self, parent_model: Type["Model"], column_name: str
|
||||||
) -> Set:
|
) -> Set:
|
||||||
"""
|
"""
|
||||||
Extracts relation ids from already populated models if they were included
|
Extracts relation ids from already populated models if they were included
|
||||||
@ -219,7 +218,7 @@ class PrefetchQuery:
|
|||||||
return list_of_ids
|
return list_of_ids
|
||||||
|
|
||||||
def _extract_required_ids(
|
def _extract_required_ids(
|
||||||
self, parent_model: Type["Model"], reverse: bool, related: str,
|
self, parent_model: Type["Model"], reverse: bool, related: str,
|
||||||
) -> Set:
|
) -> Set:
|
||||||
"""
|
"""
|
||||||
Delegates extraction of the fields to either get ids from raw sql response
|
Delegates extraction of the fields to either get ids from raw sql response
|
||||||
@ -253,11 +252,11 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _get_filter_for_prefetch(
|
def _get_filter_for_prefetch(
|
||||||
self,
|
self,
|
||||||
parent_model: Type["Model"],
|
parent_model: Type["Model"],
|
||||||
target_model: Type["Model"],
|
target_model: Type["Model"],
|
||||||
reverse: bool,
|
reverse: bool,
|
||||||
related: str,
|
related: str,
|
||||||
) -> List:
|
) -> List:
|
||||||
"""
|
"""
|
||||||
Populates where clause with condition to return only models within the
|
Populates where clause with condition to return only models within the
|
||||||
@ -298,7 +297,7 @@ class PrefetchQuery:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
def _populate_nested_related(
|
def _populate_nested_related(
|
||||||
self, model: "Model", prefetch_dict: Dict, orders_by: Dict,
|
self, model: "Model", prefetch_dict: Dict, orders_by: Dict,
|
||||||
) -> "Model":
|
) -> "Model":
|
||||||
"""
|
"""
|
||||||
Populates all related models children of parent model that are
|
Populates all related models children of parent model that are
|
||||||
@ -342,7 +341,7 @@ class PrefetchQuery:
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
async def _prefetch_related_models(
|
async def _prefetch_related_models(
|
||||||
self, models: Sequence["Model"], rows: List
|
self, models: Sequence["Model"], rows: List
|
||||||
) -> Sequence["Model"]:
|
) -> Sequence["Model"]:
|
||||||
"""
|
"""
|
||||||
Main method of the query.
|
Main method of the query.
|
||||||
@ -366,8 +365,6 @@ class PrefetchQuery:
|
|||||||
select_dict = translate_list_to_dict(self._select_related)
|
select_dict = translate_list_to_dict(self._select_related)
|
||||||
prefetch_dict = translate_list_to_dict(self._prefetch_related)
|
prefetch_dict = translate_list_to_dict(self._prefetch_related)
|
||||||
target_model = self.model
|
target_model = self.model
|
||||||
fields = self._columns
|
|
||||||
exclude_fields = self._exclude_columns
|
|
||||||
orders_by = self.order_dict
|
orders_by = self.order_dict
|
||||||
for related in prefetch_dict.keys():
|
for related in prefetch_dict.keys():
|
||||||
await self._extract_related_models(
|
await self._extract_related_models(
|
||||||
@ -375,8 +372,7 @@ class PrefetchQuery:
|
|||||||
target_model=target_model,
|
target_model=target_model,
|
||||||
prefetch_dict=prefetch_dict.get(related, {}),
|
prefetch_dict=prefetch_dict.get(related, {}),
|
||||||
select_dict=select_dict.get(related, {}),
|
select_dict=select_dict.get(related, {}),
|
||||||
fields=fields,
|
excludable=self.excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
orders_by=orders_by.get(related, {}),
|
orders_by=orders_by.get(related, {}),
|
||||||
)
|
)
|
||||||
final_models = []
|
final_models = []
|
||||||
@ -389,14 +385,13 @@ class PrefetchQuery:
|
|||||||
return models
|
return models
|
||||||
|
|
||||||
async def _extract_related_models( # noqa: CFQ002, CCR001
|
async def _extract_related_models( # noqa: CFQ002, CCR001
|
||||||
self,
|
self,
|
||||||
related: str,
|
related: str,
|
||||||
target_model: Type["Model"],
|
target_model: Type["Model"],
|
||||||
prefetch_dict: Dict,
|
prefetch_dict: Dict,
|
||||||
select_dict: Dict,
|
select_dict: Dict,
|
||||||
fields: Union[Set[Any], Dict[Any, Any], None],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Union[Set[Any], Dict[Any, Any], None],
|
orders_by: Dict,
|
||||||
orders_by: Dict,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Constructs queries with required ids and extracts data with fields that should
|
Constructs queries with required ids and extracts data with fields that should
|
||||||
@ -424,8 +419,6 @@ class PrefetchQuery:
|
|||||||
:return: None
|
:return: None
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
fields = target_model.get_included(fields, related)
|
|
||||||
exclude_fields = target_model.get_excluded(exclude_fields, related)
|
|
||||||
target_field = target_model.Meta.model_fields[related]
|
target_field = target_model.Meta.model_fields[related]
|
||||||
target_field = cast(Type["ForeignKeyField"], target_field)
|
target_field = cast(Type["ForeignKeyField"], target_field)
|
||||||
reverse = False
|
reverse = False
|
||||||
@ -450,14 +443,11 @@ class PrefetchQuery:
|
|||||||
related_field_name = parent_model.get_related_field_name(
|
related_field_name = parent_model.get_related_field_name(
|
||||||
target_field=target_field
|
target_field=target_field
|
||||||
)
|
)
|
||||||
fields = add_relation_field_to_fields(
|
|
||||||
fields=fields, related_field_name=related_field_name
|
|
||||||
)
|
|
||||||
table_prefix, rows = await self._run_prefetch_query(
|
table_prefix, rows = await self._run_prefetch_query(
|
||||||
target_field=target_field,
|
target_field=target_field,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
filter_clauses=filter_clauses,
|
filter_clauses=filter_clauses,
|
||||||
|
related_field_name=related_field_name
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
rows = []
|
rows = []
|
||||||
@ -472,8 +462,7 @@ class PrefetchQuery:
|
|||||||
select_dict=self._get_select_related_if_apply(
|
select_dict=self._get_select_related_if_apply(
|
||||||
subrelated, select_dict
|
subrelated, select_dict
|
||||||
),
|
),
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
orders_by=self._get_select_related_if_apply(subrelated, orders_by),
|
orders_by=self._get_select_related_if_apply(subrelated, orders_by),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -483,8 +472,7 @@ class PrefetchQuery:
|
|||||||
parent_model=parent_model,
|
parent_model=parent_model,
|
||||||
target_field=target_field,
|
target_field=target_field,
|
||||||
table_prefix=table_prefix,
|
table_prefix=table_prefix,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
prefetch_dict=prefetch_dict,
|
prefetch_dict=prefetch_dict,
|
||||||
orders_by=orders_by,
|
orders_by=orders_by,
|
||||||
)
|
)
|
||||||
@ -496,11 +484,11 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def _run_prefetch_query(
|
async def _run_prefetch_query(
|
||||||
self,
|
self,
|
||||||
target_field: Type["BaseField"],
|
target_field: Type["BaseField"],
|
||||||
fields: Union[Set[Any], Dict[Any, Any], None],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Union[Set[Any], Dict[Any, Any], None],
|
filter_clauses: List,
|
||||||
filter_clauses: List,
|
related_field_name: str
|
||||||
) -> Tuple[str, List]:
|
) -> Tuple[str, List]:
|
||||||
"""
|
"""
|
||||||
Actually runs the queries against the database and populates the raw response
|
Actually runs the queries against the database and populates the raw response
|
||||||
@ -511,10 +499,6 @@ class PrefetchQuery:
|
|||||||
|
|
||||||
:param target_field: ormar field with relation definition
|
:param target_field: ormar field with relation definition
|
||||||
:type target_field: Type["BaseField"]
|
:type target_field: Type["BaseField"]
|
||||||
:param fields: fields to include
|
|
||||||
:type fields: Union[Set[Any], Dict[Any, Any], None]
|
|
||||||
:param exclude_fields: fields to exclude
|
|
||||||
:type exclude_fields: Union[Set[Any], Dict[Any, Any], None]
|
|
||||||
:param filter_clauses: list of clauses, actually one clause with ids of relation
|
:param filter_clauses: list of clauses, actually one clause with ids of relation
|
||||||
:type filter_clauses: List[sqlalchemy.sql.elements.TextClause]
|
:type filter_clauses: List[sqlalchemy.sql.elements.TextClause]
|
||||||
:return: table prefix and raw rows from sql response
|
:return: table prefix and raw rows from sql response
|
||||||
@ -533,6 +517,11 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
self.already_extracted.setdefault(target_name, {})["prefix"] = table_prefix
|
self.already_extracted.setdefault(target_name, {})["prefix"] = table_prefix
|
||||||
|
|
||||||
|
model_excludable = excludable.get(model_cls=target_model, alias=table_prefix)
|
||||||
|
if model_excludable.include and not model_excludable.is_included(
|
||||||
|
related_field_name):
|
||||||
|
model_excludable.set_values({related_field_name}, is_exclude=False)
|
||||||
|
|
||||||
qry = Query(
|
qry = Query(
|
||||||
model_cls=query_target,
|
model_cls=query_target,
|
||||||
select_related=select_related,
|
select_related=select_related,
|
||||||
@ -540,8 +529,7 @@ class PrefetchQuery:
|
|||||||
exclude_clauses=[],
|
exclude_clauses=[],
|
||||||
offset=None,
|
offset=None,
|
||||||
limit_count=None,
|
limit_count=None,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
order_bys=None,
|
order_bys=None,
|
||||||
limit_raw_sql=False,
|
limit_raw_sql=False,
|
||||||
)
|
)
|
||||||
@ -571,7 +559,7 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _update_already_loaded_rows( # noqa: CFQ002
|
def _update_already_loaded_rows( # noqa: CFQ002
|
||||||
self, target_field: Type["BaseField"], prefetch_dict: Dict, orders_by: Dict,
|
self, target_field: Type["BaseField"], prefetch_dict: Dict, orders_by: Dict,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Updates models that are already loaded, usually children of children.
|
Updates models that are already loaded, usually children of children.
|
||||||
@ -590,15 +578,14 @@ class PrefetchQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _populate_rows( # noqa: CFQ002
|
def _populate_rows( # noqa: CFQ002
|
||||||
self,
|
self,
|
||||||
rows: List,
|
rows: List,
|
||||||
target_field: Type["ForeignKeyField"],
|
target_field: Type["ForeignKeyField"],
|
||||||
parent_model: Type["Model"],
|
parent_model: Type["Model"],
|
||||||
table_prefix: str,
|
table_prefix: str,
|
||||||
fields: Union[Set[Any], Dict[Any, Any], None],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Union[Set[Any], Dict[Any, Any], None],
|
prefetch_dict: Dict,
|
||||||
prefetch_dict: Dict,
|
orders_by: Dict,
|
||||||
orders_by: Dict,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Instantiates children models extracted from given relation.
|
Instantiates children models extracted from given relation.
|
||||||
@ -610,6 +597,8 @@ class PrefetchQuery:
|
|||||||
already_extracted dictionary. Later those instances will be fetched by ids
|
already_extracted dictionary. Later those instances will be fetched by ids
|
||||||
and set on the parent model after sorting if needed.
|
and set on the parent model after sorting if needed.
|
||||||
|
|
||||||
|
:param excludable: structure of fields to include and exclude
|
||||||
|
:type excludable: ExcludableItems
|
||||||
:param rows: raw sql response from the prefetch query
|
:param rows: raw sql response from the prefetch query
|
||||||
:type rows: List[sqlalchemy.engine.result.RowProxy]
|
:type rows: List[sqlalchemy.engine.result.RowProxy]
|
||||||
:param target_field: field with relation definition from parent model
|
:param target_field: field with relation definition from parent model
|
||||||
@ -618,10 +607,6 @@ class PrefetchQuery:
|
|||||||
:type parent_model: Type[Model]
|
:type parent_model: Type[Model]
|
||||||
:param table_prefix: prefix of the target table from current relation
|
:param table_prefix: prefix of the target table from current relation
|
||||||
:type table_prefix: str
|
:type table_prefix: str
|
||||||
:param fields: fields to include
|
|
||||||
:type fields: Union[Set[Any], Dict[Any, Any], None]
|
|
||||||
:param exclude_fields: fields to exclude
|
|
||||||
:type exclude_fields: Union[Set[Any], Dict[Any, Any], None]
|
|
||||||
:param prefetch_dict: dictionaries of related models to prefetch
|
:param prefetch_dict: dictionaries of related models to prefetch
|
||||||
:type prefetch_dict: Dict
|
:type prefetch_dict: Dict
|
||||||
:param orders_by: dictionary of order by clauses by model
|
:param orders_by: dictionary of order by clauses by model
|
||||||
@ -629,16 +614,16 @@ class PrefetchQuery:
|
|||||||
"""
|
"""
|
||||||
target_model = target_field.to
|
target_model = target_field.to
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
# TODO Fix fields
|
||||||
field_name = parent_model.get_related_field_name(target_field=target_field)
|
field_name = parent_model.get_related_field_name(target_field=target_field)
|
||||||
item = target_model.extract_prefixed_table_columns(
|
item = target_model.extract_prefixed_table_columns(
|
||||||
item={},
|
item={},
|
||||||
row=row,
|
row=row,
|
||||||
table_prefix=table_prefix,
|
table_prefix=table_prefix,
|
||||||
fields=fields,
|
excludable=excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
)
|
)
|
||||||
item["__excluded__"] = target_model.get_names_to_exclude(
|
item["__excluded__"] = target_model.get_names_to_exclude(
|
||||||
fields=fields, exclude_fields=exclude_fields
|
excludable=excludable, alias=table_prefix
|
||||||
)
|
)
|
||||||
instance = target_model(**item)
|
instance = target_model(**item)
|
||||||
instance = self._populate_nested_related(
|
instance = self._populate_nested_related(
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import sqlalchemy
|
|||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
|
||||||
import ormar # noqa I100
|
import ormar # noqa I100
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.models.helpers.models import group_related_list
|
from ormar.models.helpers.models import group_related_list
|
||||||
from ormar.queryset import FilterQuery, LimitQuery, OffsetQuery, OrderQuery
|
from ormar.queryset import FilterQuery, LimitQuery, OffsetQuery, OrderQuery
|
||||||
from ormar.queryset.actions.filter_action import FilterAction
|
from ormar.queryset.actions.filter_action import FilterAction
|
||||||
@ -18,25 +19,23 @@ if TYPE_CHECKING: # pragma no cover
|
|||||||
|
|
||||||
class Query:
|
class Query:
|
||||||
def __init__( # noqa CFQ002
|
def __init__( # noqa CFQ002
|
||||||
self,
|
self,
|
||||||
model_cls: Type["Model"],
|
model_cls: Type["Model"],
|
||||||
filter_clauses: List[FilterAction],
|
filter_clauses: List[FilterAction],
|
||||||
exclude_clauses: List[FilterAction],
|
exclude_clauses: List[FilterAction],
|
||||||
select_related: List,
|
select_related: List,
|
||||||
limit_count: Optional[int],
|
limit_count: Optional[int],
|
||||||
offset: Optional[int],
|
offset: Optional[int],
|
||||||
fields: Optional[Union[Dict, Set]],
|
excludable: ExcludableItems,
|
||||||
exclude_fields: Optional[Union[Dict, Set]],
|
order_bys: Optional[List["OrderAction"]],
|
||||||
order_bys: Optional[List["OrderAction"]],
|
limit_raw_sql: bool,
|
||||||
limit_raw_sql: bool,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
self.query_offset = offset
|
self.query_offset = offset
|
||||||
self.limit_count = limit_count
|
self.limit_count = limit_count
|
||||||
self._select_related = select_related[:]
|
self._select_related = select_related[:]
|
||||||
self.filter_clauses = filter_clauses[:]
|
self.filter_clauses = filter_clauses[:]
|
||||||
self.exclude_clauses = exclude_clauses[:]
|
self.exclude_clauses = exclude_clauses[:]
|
||||||
self.fields = copy.deepcopy(fields) if fields else {}
|
self.excludable = excludable
|
||||||
self.exclude_fields = copy.deepcopy(exclude_fields) if exclude_fields else {}
|
|
||||||
|
|
||||||
self.model_cls = model_cls
|
self.model_cls = model_cls
|
||||||
self.table = self.model_cls.Meta.table
|
self.table = self.model_cls.Meta.table
|
||||||
@ -105,8 +104,7 @@ class Query:
|
|||||||
"""
|
"""
|
||||||
self_related_fields = self.model_cls.own_table_columns(
|
self_related_fields = self.model_cls.own_table_columns(
|
||||||
model=self.model_cls,
|
model=self.model_cls,
|
||||||
fields=self.fields,
|
excludable=self.excludable,
|
||||||
exclude_fields=self.exclude_fields,
|
|
||||||
use_alias=True,
|
use_alias=True,
|
||||||
)
|
)
|
||||||
self.columns = self.model_cls.Meta.alias_manager.prefixed_columns(
|
self.columns = self.model_cls.Meta.alias_manager.prefixed_columns(
|
||||||
@ -121,8 +119,6 @@ class Query:
|
|||||||
related_models = group_related_list(self._select_related)
|
related_models = group_related_list(self._select_related)
|
||||||
|
|
||||||
for related in related_models:
|
for related in related_models:
|
||||||
fields = self.model_cls.get_included(self.fields, related)
|
|
||||||
exclude_fields = self.model_cls.get_excluded(self.exclude_fields, related)
|
|
||||||
remainder = None
|
remainder = None
|
||||||
if isinstance(related_models, dict) and related_models[related]:
|
if isinstance(related_models, dict) and related_models[related]:
|
||||||
remainder = related_models[related]
|
remainder = related_models[related]
|
||||||
@ -130,8 +126,7 @@ class Query:
|
|||||||
used_aliases=self.used_aliases,
|
used_aliases=self.used_aliases,
|
||||||
select_from=self.select_from,
|
select_from=self.select_from,
|
||||||
columns=self.columns,
|
columns=self.columns,
|
||||||
fields=fields,
|
excludable=self.excludable,
|
||||||
exclude_fields=exclude_fields,
|
|
||||||
order_columns=self.order_columns,
|
order_columns=self.order_columns,
|
||||||
sorted_orders=self.sorted_orders,
|
sorted_orders=self.sorted_orders,
|
||||||
main_model=self.model_cls,
|
main_model=self.model_cls,
|
||||||
@ -196,7 +191,7 @@ class Query:
|
|||||||
return expr
|
return expr
|
||||||
|
|
||||||
def _apply_expression_modifiers(
|
def _apply_expression_modifiers(
|
||||||
self, expr: sqlalchemy.sql.select
|
self, expr: sqlalchemy.sql.select
|
||||||
) -> sqlalchemy.sql.select:
|
) -> sqlalchemy.sql.select:
|
||||||
"""
|
"""
|
||||||
Receives the select query (might be join) and applies:
|
Receives the select query (might be join) and applies:
|
||||||
@ -231,5 +226,3 @@ class Query:
|
|||||||
self.select_from = []
|
self.select_from = []
|
||||||
self.columns = []
|
self.columns = []
|
||||||
self.used_aliases = []
|
self.used_aliases = []
|
||||||
self.fields = {}
|
|
||||||
self.exclude_fields = {}
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ from sqlalchemy import bindparam
|
|||||||
import ormar # noqa I100
|
import ormar # noqa I100
|
||||||
from ormar import MultipleMatches, NoMatch
|
from ormar import MultipleMatches, NoMatch
|
||||||
from ormar.exceptions import ModelError, ModelPersistenceError, QueryDefinitionError
|
from ormar.exceptions import ModelError, ModelPersistenceError, QueryDefinitionError
|
||||||
|
from ormar.models.excludable import ExcludableItems
|
||||||
from ormar.queryset import FilterQuery
|
from ormar.queryset import FilterQuery
|
||||||
from ormar.queryset.actions.order_action import OrderAction
|
from ormar.queryset.actions.order_action import OrderAction
|
||||||
from ormar.queryset.clause import QueryClause
|
from ormar.queryset.clause import QueryClause
|
||||||
@ -41,18 +42,17 @@ class QuerySet(Generic[T]):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__( # noqa CFQ002
|
def __init__( # noqa CFQ002
|
||||||
self,
|
self,
|
||||||
model_cls: Optional[Type[T]] = None,
|
model_cls: Optional[Type[T]] = None,
|
||||||
filter_clauses: List = None,
|
filter_clauses: List = None,
|
||||||
exclude_clauses: List = None,
|
exclude_clauses: List = None,
|
||||||
select_related: List = None,
|
select_related: List = None,
|
||||||
limit_count: int = None,
|
limit_count: int = None,
|
||||||
offset: int = None,
|
offset: int = None,
|
||||||
columns: Dict = None,
|
excludable: ExcludableItems = None,
|
||||||
exclude_columns: Dict = None,
|
order_bys: List = None,
|
||||||
order_bys: List = None,
|
prefetch_related: List = None,
|
||||||
prefetch_related: List = None,
|
limit_raw_sql: bool = False,
|
||||||
limit_raw_sql: bool = False,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
self.model_cls = model_cls
|
self.model_cls = model_cls
|
||||||
self.filter_clauses = [] if filter_clauses is None else filter_clauses
|
self.filter_clauses = [] if filter_clauses is None else filter_clauses
|
||||||
@ -61,15 +61,14 @@ class QuerySet(Generic[T]):
|
|||||||
self._prefetch_related = [] if prefetch_related is None else prefetch_related
|
self._prefetch_related = [] if prefetch_related is None else prefetch_related
|
||||||
self.limit_count = limit_count
|
self.limit_count = limit_count
|
||||||
self.query_offset = offset
|
self.query_offset = offset
|
||||||
self._columns = columns or {}
|
self._excludable = excludable or ExcludableItems()
|
||||||
self._exclude_columns = exclude_columns or {}
|
|
||||||
self.order_bys = order_bys or []
|
self.order_bys = order_bys or []
|
||||||
self.limit_sql_raw = limit_raw_sql
|
self.limit_sql_raw = limit_raw_sql
|
||||||
|
|
||||||
def __get__(
|
def __get__(
|
||||||
self,
|
self,
|
||||||
instance: Optional[Union["QuerySet", "QuerysetProxy"]],
|
instance: Optional[Union["QuerySet", "QuerysetProxy"]],
|
||||||
owner: Union[Type[T], Type["QuerysetProxy"]],
|
owner: Union[Type[T], Type["QuerysetProxy"]],
|
||||||
) -> "QuerySet":
|
) -> "QuerySet":
|
||||||
if issubclass(owner, ormar.Model):
|
if issubclass(owner, ormar.Model):
|
||||||
if owner.Meta.requires_ref_update:
|
if owner.Meta.requires_ref_update:
|
||||||
@ -107,7 +106,7 @@ class QuerySet(Generic[T]):
|
|||||||
return self.model_cls
|
return self.model_cls
|
||||||
|
|
||||||
async def _prefetch_related_models(
|
async def _prefetch_related_models(
|
||||||
self, models: Sequence[Optional["T"]], rows: List
|
self, models: Sequence[Optional["T"]], rows: List
|
||||||
) -> Sequence[Optional["T"]]:
|
) -> Sequence[Optional["T"]]:
|
||||||
"""
|
"""
|
||||||
Performs prefetch query for selected models names.
|
Performs prefetch query for selected models names.
|
||||||
@ -121,8 +120,7 @@ class QuerySet(Generic[T]):
|
|||||||
"""
|
"""
|
||||||
query = PrefetchQuery(
|
query = PrefetchQuery(
|
||||||
model_cls=self.model,
|
model_cls=self.model,
|
||||||
fields=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_fields=self._exclude_columns,
|
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
orders_by=self.order_bys,
|
orders_by=self.order_bys,
|
||||||
@ -142,8 +140,7 @@ class QuerySet(Generic[T]):
|
|||||||
self.model.from_row(
|
self.model.from_row(
|
||||||
row=row,
|
row=row,
|
||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
fields=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_fields=self._exclude_columns,
|
|
||||||
source_model=self.model,
|
source_model=self.model,
|
||||||
)
|
)
|
||||||
for row in rows
|
for row in rows
|
||||||
@ -186,7 +183,7 @@ class QuerySet(Generic[T]):
|
|||||||
return self.model_meta.table
|
return self.model_meta.table
|
||||||
|
|
||||||
def build_select_expression(
|
def build_select_expression(
|
||||||
self, limit: int = None, offset: int = None, order_bys: List = None,
|
self, limit: int = None, offset: int = None, order_bys: List = None,
|
||||||
) -> sqlalchemy.sql.select:
|
) -> sqlalchemy.sql.select:
|
||||||
"""
|
"""
|
||||||
Constructs the actual database query used in the QuerySet.
|
Constructs the actual database query used in the QuerySet.
|
||||||
@ -208,8 +205,7 @@ class QuerySet(Generic[T]):
|
|||||||
exclude_clauses=self.exclude_clauses,
|
exclude_clauses=self.exclude_clauses,
|
||||||
offset=offset or self.query_offset,
|
offset=offset or self.query_offset,
|
||||||
limit_count=limit or self.limit_count,
|
limit_count=limit or self.limit_count,
|
||||||
fields=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_fields=self._exclude_columns,
|
|
||||||
order_bys=order_bys or self.order_bys,
|
order_bys=order_bys or self.order_bys,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
)
|
)
|
||||||
@ -265,8 +261,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=select_related,
|
select_related=select_related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
@ -321,8 +316,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=related,
|
select_related=related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
@ -357,14 +351,14 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=related,
|
prefetch_related=related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
)
|
)
|
||||||
|
|
||||||
def fields(self, columns: Union[List, str, Set, Dict]) -> "QuerySet":
|
def fields(self, columns: Union[List, str, Set, Dict],
|
||||||
|
_is_exclude: bool = False) -> "QuerySet":
|
||||||
"""
|
"""
|
||||||
With `fields()` you can select subset of model columns to limit the data load.
|
With `fields()` you can select subset of model columns to limit the data load.
|
||||||
|
|
||||||
@ -407,15 +401,10 @@ class QuerySet(Generic[T]):
|
|||||||
:return: QuerySet
|
:return: QuerySet
|
||||||
:rtype: QuerySet
|
:rtype: QuerySet
|
||||||
"""
|
"""
|
||||||
if isinstance(columns, str):
|
excludable = ExcludableItems.from_excludable(self._excludable)
|
||||||
columns = [columns]
|
excludable.build(items=columns,
|
||||||
|
model_cls=self.model_cls,
|
||||||
# TODO: Flatten all excludes into one dict-like structure with alias + model key
|
is_exclude=_is_exclude)
|
||||||
current_included = self._columns
|
|
||||||
if not isinstance(columns, dict):
|
|
||||||
current_included = update_dict_from_list(current_included, columns)
|
|
||||||
else:
|
|
||||||
current_included = update(current_included, columns)
|
|
||||||
|
|
||||||
return self.__class__(
|
return self.__class__(
|
||||||
model_cls=self.model,
|
model_cls=self.model,
|
||||||
@ -424,8 +413,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=current_included,
|
excludable=excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
@ -458,28 +446,7 @@ class QuerySet(Generic[T]):
|
|||||||
:return: QuerySet
|
:return: QuerySet
|
||||||
:rtype: QuerySet
|
:rtype: QuerySet
|
||||||
"""
|
"""
|
||||||
if isinstance(columns, str):
|
return self.fields(columns=columns, _is_exclude=True)
|
||||||
columns = [columns]
|
|
||||||
|
|
||||||
current_excluded = self._exclude_columns
|
|
||||||
if not isinstance(columns, dict):
|
|
||||||
current_excluded = update_dict_from_list(current_excluded, columns)
|
|
||||||
else:
|
|
||||||
current_excluded = update(current_excluded, columns)
|
|
||||||
|
|
||||||
return self.__class__(
|
|
||||||
model_cls=self.model,
|
|
||||||
filter_clauses=self.filter_clauses,
|
|
||||||
exclude_clauses=self.exclude_clauses,
|
|
||||||
select_related=self._select_related,
|
|
||||||
limit_count=self.limit_count,
|
|
||||||
offset=self.query_offset,
|
|
||||||
columns=self._columns,
|
|
||||||
exclude_columns=current_excluded,
|
|
||||||
order_bys=self.order_bys,
|
|
||||||
prefetch_related=self._prefetch_related,
|
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
|
||||||
)
|
|
||||||
|
|
||||||
def order_by(self, columns: Union[List, str]) -> "QuerySet":
|
def order_by(self, columns: Union[List, str]) -> "QuerySet":
|
||||||
"""
|
"""
|
||||||
@ -529,8 +496,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=order_bys,
|
order_bys=order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
@ -642,8 +608,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=limit_count,
|
limit_count=limit_count,
|
||||||
offset=query_offset,
|
offset=query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=self.limit_sql_raw,
|
limit_raw_sql=self.limit_sql_raw,
|
||||||
@ -671,8 +636,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=limit_count,
|
limit_count=limit_count,
|
||||||
offset=self.query_offset,
|
offset=self.query_offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=limit_raw_sql,
|
limit_raw_sql=limit_raw_sql,
|
||||||
@ -700,8 +664,7 @@ class QuerySet(Generic[T]):
|
|||||||
select_related=self._select_related,
|
select_related=self._select_related,
|
||||||
limit_count=self.limit_count,
|
limit_count=self.limit_count,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
columns=self._columns,
|
excludable=self._excludable,
|
||||||
exclude_columns=self._exclude_columns,
|
|
||||||
order_bys=self.order_bys,
|
order_bys=self.order_bys,
|
||||||
prefetch_related=self._prefetch_related,
|
prefetch_related=self._prefetch_related,
|
||||||
limit_raw_sql=limit_raw_sql,
|
limit_raw_sql=limit_raw_sql,
|
||||||
@ -724,12 +687,12 @@ class QuerySet(Generic[T]):
|
|||||||
expr = self.build_select_expression(
|
expr = self.build_select_expression(
|
||||||
limit=1,
|
limit=1,
|
||||||
order_bys=[
|
order_bys=[
|
||||||
OrderAction(
|
OrderAction(
|
||||||
order_str=f"{self.model.Meta.pkname}",
|
order_str=f"{self.model.Meta.pkname}",
|
||||||
model_cls=self.model_cls, # type: ignore
|
model_cls=self.model_cls, # type: ignore
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
+ self.order_bys,
|
+ self.order_bys,
|
||||||
)
|
)
|
||||||
rows = await self.database.fetch_all(expr)
|
rows = await self.database.fetch_all(expr)
|
||||||
processed_rows = self._process_query_result_rows(rows)
|
processed_rows = self._process_query_result_rows(rows)
|
||||||
@ -760,12 +723,12 @@ class QuerySet(Generic[T]):
|
|||||||
expr = self.build_select_expression(
|
expr = self.build_select_expression(
|
||||||
limit=1,
|
limit=1,
|
||||||
order_bys=[
|
order_bys=[
|
||||||
OrderAction(
|
OrderAction(
|
||||||
order_str=f"-{self.model.Meta.pkname}",
|
order_str=f"-{self.model.Meta.pkname}",
|
||||||
model_cls=self.model_cls, # type: ignore
|
model_cls=self.model_cls, # type: ignore
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
+ self.order_bys,
|
+ self.order_bys,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
expr = self.build_select_expression()
|
expr = self.build_select_expression()
|
||||||
@ -868,9 +831,9 @@ class QuerySet(Generic[T]):
|
|||||||
|
|
||||||
# refresh server side defaults
|
# refresh server side defaults
|
||||||
if any(
|
if any(
|
||||||
field.server_default is not None
|
field.server_default is not None
|
||||||
for name, field in self.model.Meta.model_fields.items()
|
for name, field in self.model.Meta.model_fields.items()
|
||||||
if name not in kwargs
|
if name not in kwargs
|
||||||
):
|
):
|
||||||
instance = await instance.load()
|
instance = await instance.load()
|
||||||
instance.set_save_status(True)
|
instance.set_save_status(True)
|
||||||
@ -905,7 +868,7 @@ class QuerySet(Generic[T]):
|
|||||||
objt.set_save_status(True)
|
objt.set_save_status(True)
|
||||||
|
|
||||||
async def bulk_update( # noqa: CCR001
|
async def bulk_update( # noqa: CCR001
|
||||||
self, objects: List[T], columns: List[str] = None
|
self, objects: List[T], columns: List[str] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Performs bulk update in one database session to speed up the process.
|
Performs bulk update in one database session to speed up the process.
|
||||||
|
|||||||
Reference in New Issue
Block a user