add possibility to exclude/include fields (refactor to excludableitems), fix for through model only on related side of the relation, fix for exclude of through model related models

This commit is contained in:
collerek
2021-03-01 19:26:33 +01:00
parent 0c781c4d52
commit a99000d2c0
15 changed files with 313 additions and 430 deletions

View File

@ -3,11 +3,9 @@ from typing import (
Dict,
List,
Optional,
Set,
TYPE_CHECKING,
Type,
TypeVar,
Union,
cast,
)
@ -17,7 +15,6 @@ from ormar.models import NewBaseModel # noqa: I202
from ormar.models.excludable import ExcludableItems
from ormar.models.helpers.models import group_related_list
if TYPE_CHECKING: # pragma: no cover
from ormar.fields import ForeignKeyField
from ormar.models import T
@ -36,6 +33,7 @@ class ModelRow(NewBaseModel):
related_field: Type["ForeignKeyField"] = None,
excludable: ExcludableItems = None,
current_relation_str: str = "",
proxy_source_model: Optional[Type["ModelRow"]] = None,
) -> Optional[T]:
"""
Model method to convert raw sql row from database into ormar.Model instance.
@ -91,12 +89,10 @@ class ModelRow(NewBaseModel):
excludable=excludable,
current_relation_str=current_relation_str,
source_model=source_model,
proxy_source_model=proxy_source_model, # type: ignore
)
item = cls.extract_prefixed_table_columns(
item=item,
row=row,
table_prefix=table_prefix,
excludable=excludable
item=item, row=row, table_prefix=table_prefix, excludable=excludable
)
instance: Optional[T] = None
@ -117,6 +113,7 @@ class ModelRow(NewBaseModel):
related_models: Any,
excludable: ExcludableItems,
current_relation_str: str = None,
proxy_source_model: Type[T] = None,
) -> dict:
"""
Traverses structure of related models and populates the nested models
@ -165,20 +162,22 @@ class ModelRow(NewBaseModel):
excludable=excludable,
current_relation_str=relation_str,
source_model=source_model,
proxy_source_model=proxy_source_model,
)
item[model_cls.get_column_name_from_alias(related)] = child
if field.is_multi and child:
# TODO: way to figure out which side should be populated?
through_name = cls.Meta.model_fields[related].through.get_name()
# for now it's nested dict, should be instance?
through_child = cls.populate_through_instance(
row=row,
related=related,
through_name=through_name,
excludable=excludable
excludable=excludable,
)
item[through_name] = through_child
setattr(child, through_name, through_child)
if child.__class__ != proxy_source_model:
setattr(child, through_name, through_child)
else:
item[through_name] = through_child
child.set_save_status(True)
return item
@ -189,19 +188,24 @@ class ModelRow(NewBaseModel):
row: sqlalchemy.engine.ResultProxy,
through_name: str,
related: str,
excludable: ExcludableItems
) -> Dict:
# TODO: fix excludes and includes and docstring
excludable: ExcludableItems,
) -> "ModelRow":
model_cls = cls.Meta.model_fields[through_name].to
table_prefix = cls.Meta.alias_manager.resolve_relation_alias(
from_model=cls, relation_name=related
)
child = model_cls.extract_prefixed_table_columns(
item={},
row=row,
excludable=excludable,
table_prefix=table_prefix
# remove relations on through field
model_excludable = excludable.get(model_cls=model_cls, alias=table_prefix)
model_excludable.set_values(
value=model_cls.extract_related_names(), is_exclude=True
)
child_dict = model_cls.extract_prefixed_table_columns(
item={}, row=row, excludable=excludable, table_prefix=table_prefix
)
child_dict["__excluded__"] = model_cls.get_names_to_exclude(
excludable=excludable, alias=table_prefix
)
child = model_cls(**child_dict) # type: ignore
return child
@classmethod
@ -210,7 +214,7 @@ class ModelRow(NewBaseModel):
item: dict,
row: sqlalchemy.engine.result.ResultProxy,
table_prefix: str,
excludable: ExcludableItems
excludable: ExcludableItems,
) -> Dict:
"""
Extracts own fields from raw sql result, using a given prefix.
@ -242,10 +246,7 @@ class ModelRow(NewBaseModel):
source = row._row if cls.db_backend_name() == "postgresql" else row
selected_columns = cls.own_table_columns(
model=cls,
excludable=excludable,
alias=table_prefix,
use_alias=False,
model=cls, excludable=excludable, alias=table_prefix, use_alias=False,
)
for column in cls.Meta.table.columns: