fix isnull typo and formatting

This commit is contained in:
collerek
2021-04-22 18:55:45 +02:00
parent 0fcdcbdf1d
commit 2088cb16b5
38 changed files with 1784 additions and 458 deletions

View File

@ -5,7 +5,7 @@
#### is\_field\_an\_forward\_ref
```python
is_field_an_forward_ref(field: Type["BaseField"]) -> bool
is_field_an_forward_ref(field: "BaseField") -> bool
```
Checks if field is a relation field and whether any of the referenced models
@ -91,7 +91,7 @@ extraction of ormar model_fields.
#### group\_related\_list
```python
group_related_list(list_: List) -> Dict
group_related_list(list_: List) -> collections.OrderedDict
```
Translates the list of related strings into a dictionary.

View File

@ -5,7 +5,7 @@
#### create\_pydantic\_field
```python
create_pydantic_field(field_name: str, model: Type["Model"], model_field: Type["ManyToManyField"]) -> None
create_pydantic_field(field_name: str, model: Type["Model"], model_field: "ManyToManyField") -> None
```
Registers pydantic field on through model that leads to passed model
@ -38,32 +38,6 @@ field_name. Returns a pydantic field with type of field_name field type.
`(pydantic.ModelField)`: newly created pydantic field
<a name="models.helpers.pydantic.populate_default_pydantic_field_value"></a>
#### populate\_default\_pydantic\_field\_value
```python
populate_default_pydantic_field_value(ormar_field: Type["BaseField"], field_name: str, attrs: dict) -> dict
```
Grabs current value of the ormar Field in class namespace
(so the default_value declared on ormar model if set)
and converts it to pydantic.FieldInfo
that pydantic is able to extract later.
On FieldInfo there are saved all needed params like max_length of the string
and other constraints that pydantic can use to build
it's own field validation used by ormar.
**Arguments**:
- `ormar_field (ormar Field)`: field to convert
- `field_name (str)`: field to convert name
- `attrs (Dict)`: current class namespace
**Returns**:
`(Dict)`: updated namespace dict
<a name="models.helpers.pydantic.populate_pydantic_default_values"></a>
#### populate\_pydantic\_default\_values
@ -76,7 +50,7 @@ dictionary of the class. Fields declared on model are all subclasses of the
BaseField class.
Trigger conversion of ormar field into pydantic FieldInfo, which has all needed
paramaters saved.
parameters saved.
Overwrites the annotations of ormar fields to corresponding types declared on
ormar fields (constructed dynamically for relations).

View File

@ -5,7 +5,7 @@
#### register\_relation\_on\_build
```python
register_relation_on_build(field: Type["ForeignKeyField"]) -> None
register_relation_on_build(field: "ForeignKeyField") -> None
```
Registers ForeignKey relation in alias_manager to set a table_prefix.
@ -23,7 +23,7 @@ aliases for proper sql joins.
#### register\_many\_to\_many\_relation\_on\_build
```python
register_many_to_many_relation_on_build(field: Type["ManyToManyField"]) -> None
register_many_to_many_relation_on_build(field: "ManyToManyField") -> None
```
Registers connection between through model and both sides of the m2m relation.
@ -43,7 +43,7 @@ By default relation name is a model.name.lower().
#### expand\_reverse\_relationship
```python
expand_reverse_relationship(model_field: Type["ForeignKeyField"]) -> None
expand_reverse_relationship(model_field: "ForeignKeyField") -> None
```
If the reverse relation has not been set before it's set here.
@ -76,7 +76,7 @@ If the reverse relation has not been set before it's set here.
#### register\_reverse\_model\_fields
```python
register_reverse_model_fields(model_field: Type["ForeignKeyField"]) -> None
register_reverse_model_fields(model_field: "ForeignKeyField") -> None
```
Registers reverse ForeignKey field on related model.
@ -93,7 +93,7 @@ Autogenerated reverse fields also set related_name to the original field name.
#### register\_through\_shortcut\_fields
```python
register_through_shortcut_fields(model_field: Type["ManyToManyField"]) -> None
register_through_shortcut_fields(model_field: "ManyToManyField") -> None
```
Registers m2m relation through shortcut on both ends of the relation.
@ -106,7 +106,7 @@ Registers m2m relation through shortcut on both ends of the relation.
#### register\_relation\_in\_alias\_manager
```python
register_relation_in_alias_manager(field: Type["ForeignKeyField"]) -> None
register_relation_in_alias_manager(field: "ForeignKeyField") -> None
```
Registers the relation (and reverse relation) in alias manager.
@ -125,7 +125,7 @@ fk - register_relation_on_build
#### verify\_related\_name\_dont\_duplicate
```python
verify_related_name_dont_duplicate(related_name: str, model_field: Type["ForeignKeyField"]) -> None
verify_related_name_dont_duplicate(related_name: str, model_field: "ForeignKeyField") -> None
```
Verifies whether the used related_name (regardless of the fact if user defined or
@ -150,7 +150,7 @@ model
#### reverse\_field\_not\_already\_registered
```python
reverse_field_not_already_registered(model_field: Type["ForeignKeyField"]) -> bool
reverse_field_not_already_registered(model_field: "ForeignKeyField") -> bool
```
Checks if child is already registered in parents pydantic fields.

View File

@ -5,7 +5,7 @@
#### adjust\_through\_many\_to\_many\_model
```python
adjust_through_many_to_many_model(model_field: Type["ManyToManyField"]) -> None
adjust_through_many_to_many_model(model_field: "ManyToManyField") -> None
```
Registers m2m relation on through model.
@ -21,7 +21,7 @@ Sets pydantic fields with child and parent model types.
#### create\_and\_append\_m2m\_fk
```python
create_and_append_m2m_fk(model: Type["Model"], model_field: Type["ManyToManyField"], field_name: str) -> None
create_and_append_m2m_fk(model: Type["Model"], model_field: "ManyToManyField", field_name: str) -> None
```
Registers sqlalchemy Column with sqlalchemy.ForeignKey leading to the model.
@ -98,6 +98,72 @@ or pkname validation fails.
`(Tuple[Optional[str], List[sqlalchemy.Column]])`: pkname, list of sqlalchemy columns
<a name="models.helpers.sqlalchemy._process_fields"></a>
#### \_process\_fields
```python
_process_fields(model_fields: Dict, new_model: Type["Model"]) -> Tuple[Optional[str], List[sqlalchemy.Column]]
```
Helper method.
Populates pkname and columns.
Trigger validation of primary_key - only one and required pk can be set,
cannot be pydantic_only.
Append fields to columns if it's not pydantic_only,
virtual ForeignKey or ManyToMany field.
Sets `owner` on each model_field as reference to newly created Model.
**Raises**:
- `ModelDefinitionError`: if validation of related_names fail,
or pkname validation fails.
**Arguments**:
- `model_fields (Dict[str, ormar.Field])`: dictionary of declared ormar model fields
- `new_model (Model class)`:
**Returns**:
`(Tuple[Optional[str], List[sqlalchemy.Column]])`: pkname, list of sqlalchemy columns
<a name="models.helpers.sqlalchemy._is_through_model_not_set"></a>
#### \_is\_through\_model\_not\_set
```python
_is_through_model_not_set(field: "BaseField") -> bool
```
Alias to if check that verifies if through model was created.
**Arguments**:
- `field ("BaseField")`: field to check
**Returns**:
`(bool)`: result of the check
<a name="models.helpers.sqlalchemy._is_db_field"></a>
#### \_is\_db\_field
```python
_is_db_field(field: "BaseField") -> bool
```
Alias to if check that verifies if field should be included in database.
**Arguments**:
- `field ("BaseField")`: field to check
**Returns**:
`(bool)`: result of the check
<a name="models.helpers.sqlalchemy.populate_meta_tablename_columns_and_pk"></a>
#### populate\_meta\_tablename\_columns\_and\_pk
@ -165,7 +231,7 @@ It populates name, metadata, columns and constraints.
#### update\_column\_definition
```python
update_column_definition(model: Union[Type["Model"], Type["NewBaseModel"]], field: Type["ForeignKeyField"]) -> None
update_column_definition(model: Union[Type["Model"], Type["NewBaseModel"]], field: "ForeignKeyField") -> None
```
Updates a column with a new type column based on updated parameters in FK fields.
@ -173,7 +239,7 @@ Updates a column with a new type column based on updated parameters in FK fields
**Arguments**:
- `model (Type["Model"])`: model on which columns needs to be updated
- `field (Type[ForeignKeyField])`: field with column definition that requires update
- `field (ForeignKeyField)`: field with column definition that requires update
**Returns**:

View File

@ -5,7 +5,7 @@
#### check\_if\_field\_has\_choices
```python
check_if_field_has_choices(field: Type[BaseField]) -> bool
check_if_field_has_choices(field: BaseField) -> bool
```
Checks if given field has choices populated.
@ -23,7 +23,7 @@ A if it has one, a validator for this field needs to be attached.
#### convert\_choices\_if\_needed
```python
convert_choices_if_needed(field: Type["BaseField"], value: Any) -> Tuple[Any, List]
convert_choices_if_needed(field: "BaseField", value: Any) -> Tuple[Any, List]
```
Converts dates to isoformat as fastapi can check this condition in routes
@ -37,7 +37,7 @@ Converts decimal to float with given scale.
**Arguments**:
- `field (Type[BaseField])`: ormar field to check with choices
- `field (BaseField)`: ormar field to check with choices
- `values (Dict)`: current values of the model to verify
**Returns**:
@ -48,7 +48,7 @@ Converts decimal to float with given scale.
#### validate\_choices
```python
validate_choices(field: Type["BaseField"], value: Any) -> None
validate_choices(field: "BaseField", value: Any) -> None
```
Validates if given value is in provided choices.
@ -59,7 +59,7 @@ Validates if given value is in provided choices.
**Arguments**:
- `field (Type[BaseField])`: field to validate
- `field (BaseField)`: field to validate
- `value (Any)`: value of the field
<a name="models.helpers.validation.choices_validator"></a>

View File

@ -78,12 +78,12 @@ Primary key field is always added and cannot be excluded (will be added anyway).
`(List[str])`: list of column field names or aliases
<a name="models.mixins.excludable_mixin.ExcludableMixin._update_excluded_with_related_not_required"></a>
#### \_update\_excluded\_with\_related\_not\_required
<a name="models.mixins.excludable_mixin.ExcludableMixin._update_excluded_with_related"></a>
#### \_update\_excluded\_with\_related
```python
| @classmethod
| _update_excluded_with_related_not_required(cls, exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None], nested: bool = False) -> Union[Set, Dict]
| _update_excluded_with_related(cls, exclude: Union[Set, Dict, None]) -> Set
```
Used during generation of the dict().
@ -96,7 +96,6 @@ exclusion, for nested models all related models are excluded.
**Arguments**:
- `exclude (Union[Set, Dict, None])`: set/dict with fields to exclude
- `nested (bool)`: flag setting nested models (child of previous one, not main one)
**Returns**:

View File

@ -19,7 +19,7 @@ in the end all parent (main) models should be unique.
```python
| @classmethod
| merge_instances_list(cls, result_rows: Sequence["Model"]) -> Sequence["Model"]
| merge_instances_list(cls, result_rows: List["Model"]) -> List["Model"]
```
Merges a list of models into list of unique models.
@ -41,7 +41,7 @@ populated, each instance is one row in db and some models can duplicate
```python
| @classmethod
| merge_two_instances(cls, one: "Model", other: "Model") -> "Model"
| merge_two_instances(cls, one: "Model", other: "Model", relation_map: Dict = None) -> "Model"
```
Merges current (other) Model and previous one (one) and returns the current
@ -51,6 +51,7 @@ If needed it's calling itself recurrently and merges also children models.
**Arguments**:
- `relation_map (Dict)`: map of models relations to follow
- `one (Model)`: previous model instance
- `other (Model)`: current model instance
@ -58,3 +59,30 @@ If needed it's calling itself recurrently and merges also children models.
`(Model)`: current Model instance with data merged from previous one.
<a name="models.mixins.merge_mixin.MergeModelMixin._merge_items_lists"></a>
#### \_merge\_items\_lists
```python
| @classmethod
| _merge_items_lists(cls, field_name: str, current_field: List, other_value: List, relation_map: Optional[Dict]) -> List
```
Takes two list of nested models and process them going deeper
according with the map.
If model from one's list is in other -> they are merged with relations
to follow passed from map.
If one's model is not in other it's simply appended to the list.
**Arguments**:
- `field_name (str)`: name of the current relation field
- `current_field (List[Model])`: list of nested models from one model
- `other_value (List[Model])`: list of nested models from other model
- `relation_map (Dict)`: map of relations to follow
**Returns**:
`(List[Model])`: merged list of models

View File

@ -59,7 +59,7 @@ or field name specified by related parameter.
```python
| @classmethod
| get_related_field_name(cls, target_field: Type["ForeignKeyField"]) -> str
| get_related_field_name(cls, target_field: "ForeignKeyField") -> str
```
Returns name of the relation field that should be used in prefetch query.

View File

@ -30,7 +30,7 @@ related fields.
```python
| @classmethod
| extract_related_fields(cls) -> List
| extract_related_fields(cls) -> List["ForeignKeyField"]
```
Returns List of ormar Fields for all relations declared on a model.
@ -45,7 +45,7 @@ List is cached in cls._related_fields for quicker access.
```python
| @classmethod
| extract_through_names(cls) -> Set
| extract_through_names(cls) -> Set[str]
```
Extracts related fields through names which are shortcuts to through models.
@ -84,43 +84,35 @@ related fields that are not stored as foreign keys on given model.
`(Set)`: set of model fields with non fk relation fields excluded
<a name="models.mixins.relation_mixin.RelationMixin._exclude_related_names_not_required"></a>
#### \_exclude\_related\_names\_not\_required
```python
| @classmethod
| _exclude_related_names_not_required(cls, nested: bool = False) -> Set
```
Returns a set of non mandatory related models field names.
For a main model (not nested) only nullable related field names are returned,
for nested models all related models are returned.
**Arguments**:
- `nested (bool)`: flag setting nested models (child of previous one, not main one)
**Returns**:
`(Set)`: set of non mandatory related fields
<a name="models.mixins.relation_mixin.RelationMixin._iterate_related_models"></a>
#### \_iterate\_related\_models
```python
| @classmethod
| _iterate_related_models(cls, visited: Set[Union[Type["Model"], Type["RelationMixin"]]] = None, source_relation: str = None, source_model: Union[Type["Model"], Type["RelationMixin"]] = None) -> List[str]
| _iterate_related_models(cls, node_list: NodeList = None, source_relation: str = None) -> List[str]
```
Iterates related models recursively to extract relation strings of
nested not visited models.
**Returns**:
`(List[str])`: list of relation strings to be passed to select_related
<a name="models.mixins.relation_mixin.RelationMixin._get_final_relations"></a>
#### \_get\_final\_relations
```python
| @staticmethod
| _get_final_relations(processed_relations: List, source_relation: Optional[str]) -> List[str]
```
Helper method to prefix nested relation strings with current source relation
**Arguments**:
- `visited (Set[str])`: set of already visited models
- `processed_relations (List[str])`: list of already processed relation str
- `source_relation (str)`: name of the current relation
- `source_model (Type["Model"])`: model from which relation comes in nested relations
**Returns**:

View File

@ -33,6 +33,25 @@ Translate columns into aliases (db names).
`(Dict[str, str])`: dictionary of model that is about to be saved
<a name="models.mixins.save_mixin.SavePrepareMixin._remove_not_ormar_fields"></a>
#### \_remove\_not\_ormar\_fields
```python
| @classmethod
| _remove_not_ormar_fields(cls, new_kwargs: dict) -> dict
```
Removes primary key for if it's nullable or autoincrement pk field,
and it's set to None.
**Arguments**:
- `new_kwargs (Dict[str, str])`: dictionary of model that is about to be saved
**Returns**:
`(Dict[str, str])`: dictionary of model that is about to be saved
<a name="models.mixins.save_mixin.SavePrepareMixin._remove_pk_from_kwargs"></a>
#### \_remove\_pk\_from\_kwargs
@ -52,6 +71,25 @@ and it's set to None.
`(Dict[str, str])`: dictionary of model that is about to be saved
<a name="models.mixins.save_mixin.SavePrepareMixin.parse_non_db_fields"></a>
#### parse\_non\_db\_fields
```python
| @classmethod
| parse_non_db_fields(cls, model_dict: Dict) -> Dict
```
Receives dictionary of model that is about to be saved and changes uuid fields
to strings in bulk_update.
**Arguments**:
- `model_dict (Dict)`: dictionary of model that is about to be saved
**Returns**:
`(Dict)`: dictionary of model that is about to be saved
<a name="models.mixins.save_mixin.SavePrepareMixin.substitute_models_with_pks"></a>
#### substitute\_models\_with\_pks
@ -110,3 +148,73 @@ fields with choices set to see if the value is allowed.
`(Dict)`: dictionary of model that is about to be saved
<a name="models.mixins.save_mixin.SavePrepareMixin._upsert_model"></a>
#### \_upsert\_model
```python
| @staticmethod
| async _upsert_model(instance: "Model", save_all: bool, previous_model: Optional["Model"], relation_field: Optional["ForeignKeyField"], update_count: int) -> int
```
Method updates given instance if:
* instance is not saved or
* instance have no pk or
* save_all=True flag is set
and instance is not __pk_only__.
If relation leading to instance is a ManyToMany also the through model is saved
**Arguments**:
- `instance (Model)`: current model to upsert
- `save_all (bool)`: flag if all models should be saved or only not saved ones
- `relation_field (Optional[ForeignKeyField])`: field with relation
- `previous_model (Model)`: previous model from which method came
- `update_count (int)`: no of updated models
**Returns**:
`(int)`: no of updated models
<a name="models.mixins.save_mixin.SavePrepareMixin._upsert_through_model"></a>
#### \_upsert\_through\_model
```python
| @staticmethod
| async _upsert_through_model(instance: "Model", previous_model: "Model", relation_field: "ForeignKeyField") -> None
```
Upsert through model for m2m relation.
**Arguments**:
- `instance (Model)`: current model to upsert
- `relation_field (Optional[ForeignKeyField])`: field with relation
- `previous_model (Model)`: previous model from which method came
<a name="models.mixins.save_mixin.SavePrepareMixin._update_relation_list"></a>
#### \_update\_relation\_list
```python
| async _update_relation_list(fields_list: Collection["ForeignKeyField"], follow: bool, save_all: bool, relation_map: Dict, update_count: int) -> int
```
Internal method used in save_related to follow deeper from
related models and update numbers of updated related instances.
**Arguments**:
- `fields_list (Collection["ForeignKeyField"])`: list of ormar fields to follow and save
- `relation_map (Dict)`: map of relations to follow
- `follow (bool)`: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
- `update_count (int)`: internal parameter for recursive calls -
number of updated instances
**Returns**:
`(int)`: tuple of update count and visited

View File

@ -102,7 +102,7 @@ Updates Meta parameters in child from parent if needed.
#### copy\_and\_replace\_m2m\_through\_model
```python
copy_and_replace_m2m_through_model(field: Type[ManyToManyField], field_name: str, table_name: str, parent_fields: Dict, attrs: Dict, meta: ModelMeta, base_class: Type["Model"]) -> None
copy_and_replace_m2m_through_model(field: ManyToManyField, field_name: str, table_name: str, parent_fields: Dict, attrs: Dict, meta: ModelMeta, base_class: Type["Model"]) -> None
```
Clones class with Through model for m2m relations, appends child name to the name
@ -119,7 +119,7 @@ Removes the original sqlalchemy table from metadata if it was not removed.
**Arguments**:
- `base_class (Type["Model"])`: base class model
- `field (Type[ManyToManyField])`: field with relations definition
- `field (ManyToManyField)`: field with relations definition
- `field_name (str)`: name of the relation field
- `table_name (str)`: name of the table
- `parent_fields (Dict)`: dictionary of fields to copy to new models from parent
@ -130,9 +130,7 @@ Removes the original sqlalchemy table from metadata if it was not removed.
#### copy\_data\_from\_parent\_model
```python
copy_data_from_parent_model(base_class: Type["Model"], curr_class: type, attrs: Dict, model_fields: Dict[
str, Union[Type[BaseField], Type[ForeignKeyField], Type[ManyToManyField]]
]) -> Tuple[Dict, Dict]
copy_data_from_parent_model(base_class: Type["Model"], curr_class: type, attrs: Dict, model_fields: Dict[str, Union[BaseField, ForeignKeyField, ManyToManyField]]) -> Tuple[Dict, Dict]
```
Copy the key parameters [databse, metadata, property_fields and constraints]
@ -162,9 +160,7 @@ Since relation fields requires different related_name for different children
#### extract\_from\_parents\_definition
```python
extract_from_parents_definition(base_class: type, curr_class: type, attrs: Dict, model_fields: Dict[
str, Union[Type[BaseField], Type[ForeignKeyField], Type[ManyToManyField]]
]) -> Tuple[Dict, Dict]
extract_from_parents_definition(base_class: type, curr_class: type, attrs: Dict, model_fields: Dict[str, Union[BaseField, ForeignKeyField, ManyToManyField]]) -> Tuple[Dict, Dict]
```
Extracts fields from base classes if they have valid oramr fields.

View File

@ -13,7 +13,7 @@ class ModelRow(NewBaseModel)
```python
| @classmethod
| from_row(cls, row: sqlalchemy.engine.ResultProxy, source_model: Type["Model"], select_related: List = None, related_models: Any = None, related_field: Type["ForeignKeyField"] = None, excludable: ExcludableItems = None, current_relation_str: str = "", proxy_source_model: Optional[Type["Model"]] = None) -> Optional["Model"]
| from_row(cls, row: sqlalchemy.engine.ResultProxy, source_model: Type["Model"], select_related: List = None, related_models: Any = None, related_field: "ForeignKeyField" = None, excludable: ExcludableItems = None, current_relation_str: str = "", proxy_source_model: Optional[Type["Model"]] = None, used_prefixes: List[str] = None) -> Optional["Model"]
```
Model method to convert raw sql row from database into ormar.Model instance.
@ -30,6 +30,7 @@ nested models in result.
**Arguments**:
- `used_prefixes (List[str])`: list of already extracted prefixes
- `proxy_source_model (Optional[Type["ModelRow"]])`: source model from which querysetproxy is constructed
- `excludable (ExcludableItems)`: structure of fields to include and exclude
- `current_relation_str (str)`: name of the relation field
@ -37,18 +38,37 @@ nested models in result.
- `row (sqlalchemy.engine.result.ResultProxy)`: raw result row from the database
- `select_related (List)`: list of names of related models fetched from database
- `related_models (Union[List, Dict])`: list or dict of related models
- `related_field (Type[ForeignKeyField])`: field with relation declaration
- `related_field (ForeignKeyField)`: field with relation declaration
**Returns**:
`(Optional[Model])`: returns model if model is populated from database
<a name="models.model_row.ModelRow._process_table_prefix"></a>
#### \_process\_table\_prefix
```python
| @classmethod
| _process_table_prefix(cls, source_model: Type["Model"], current_relation_str: str, related_field: "ForeignKeyField", used_prefixes: List[str]) -> str
```
**Arguments**:
- `source_model (Type[Model])`: model on which relation was defined
- `current_relation_str (str)`: current relation string
- `related_field ("ForeignKeyField")`: field with relation declaration
- `used_prefixes (List[str])`: list of already extracted prefixes
**Returns**:
`(str)`: table_prefix to use
<a name="models.model_row.ModelRow._populate_nested_models_from_row"></a>
#### \_populate\_nested\_models\_from\_row
```python
| @classmethod
| _populate_nested_models_from_row(cls, item: dict, row: sqlalchemy.engine.ResultProxy, source_model: Type["Model"], related_models: Any, excludable: ExcludableItems, table_prefix: str, current_relation_str: str = None, proxy_source_model: Type["Model"] = None) -> dict
| _populate_nested_models_from_row(cls, item: dict, row: sqlalchemy.engine.ResultProxy, source_model: Type["Model"], related_models: Any, excludable: ExcludableItems, table_prefix: str, used_prefixes: List[str], current_relation_str: str = None, proxy_source_model: Type["Model"] = None) -> dict
```
Traverses structure of related models and populates the nested models
@ -75,12 +95,48 @@ instances. In the end those instances are added to the final model dictionary.
`(Dict)`: dictionary with keys corresponding to model fields names
and values are database values
<a name="models.model_row.ModelRow.populate_through_instance"></a>
#### populate\_through\_instance
<a name="models.model_row.ModelRow._process_remainder_and_relation_string"></a>
#### \_process\_remainder\_and\_relation\_string
```python
| @staticmethod
| _process_remainder_and_relation_string(related_models: Union[Dict, List], current_relation_str: Optional[str], related: str) -> Tuple[str, Optional[Union[Dict, List]]]
```
Process remainder models and relation string
**Arguments**:
- `related_models (Union[Dict, List])`: list or dict of related models
- `current_relation_str (Optional[str])`: current relation string
- `related (str)`: name of the relation
<a name="models.model_row.ModelRow._populate_through_instance"></a>
#### \_populate\_through\_instance
```python
| @classmethod
| populate_through_instance(cls, row: sqlalchemy.engine.ResultProxy, through_name: str, related: str, excludable: ExcludableItems) -> "ModelRow"
| _populate_through_instance(cls, row: sqlalchemy.engine.ResultProxy, item: Dict, related: str, excludable: ExcludableItems, child: "Model", proxy_source_model: Optional[Type["Model"]]) -> None
```
Populates the through model on reverse side of current query.
Normally it's child class, unless the query is from queryset.
**Arguments**:
- `row (sqlalchemy.engine.ResultProxy)`: row from db result
- `item (Dict)`: parent item dict
- `related (str)`: current relation name
- `excludable (ExcludableItems)`: structure of fields to include and exclude
- `child ("Model")`: child item of parent
- `proxy_source_model (Type["Model"])`: source model from which querysetproxy is constructed
<a name="models.model_row.ModelRow._create_through_instance"></a>
#### \_create\_through\_instance
```python
| @classmethod
| _create_through_instance(cls, row: sqlalchemy.engine.ResultProxy, through_name: str, related: str, excludable: ExcludableItems) -> "ModelRow"
```
Initialize the through model from db row.

View File

@ -12,7 +12,7 @@ class Model(ModelRow)
#### upsert
```python
| async upsert(**kwargs: Any) -> "Model"
| async upsert(**kwargs: Any) -> T
```
Performs either a save or an update depending on the presence of the pk.
@ -31,7 +31,7 @@ For save kwargs are ignored, used only in update if provided.
#### save
```python
| async save() -> "Model"
| async save() -> T
```
Performs a save of given Model instance.
@ -60,7 +60,7 @@ Sets model save status to True.
#### save\_related
```python
| async save_related(follow: bool = False, visited: Set = None, update_count: int = 0) -> int
| async save_related(follow: bool = False, save_all: bool = False, relation_map: Dict = None, exclude: Union[Set, Dict] = None, update_count: int = 0, previous_model: "Model" = None, relation_field: Optional["ForeignKeyField"] = None) -> int
```
Triggers a upsert method on all related models
@ -79,10 +79,14 @@ Nested relations of those kind need to be persisted manually.
**Arguments**:
- `relation_field (Optional[ForeignKeyField])`: field with relation leading to this model
- `previous_model (Model)`: previous model from which method came
- `exclude (Union[Set, Dict])`: items to exclude during saving of relations
- `relation_map (Dict)`: map of relations to follow
- `save_all (bool)`: flag if all models should be saved or only not saved ones
- `follow (bool)`: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
- `visited (Set)`: internal parameter for recursive calls - already visited models
- `update_count (int)`: internal parameter for recursive calls -
number of updated instances
@ -90,36 +94,11 @@ number of updated instances
`(int)`: number of updated/saved models
<a name="models.model.Model._update_and_follow"></a>
#### \_update\_and\_follow
```python
| @staticmethod
| async _update_and_follow(rel: "Model", follow: bool, visited: Set, update_count: int) -> Tuple[int, Set]
```
Internal method used in save_related to follow related models and update numbers
of updated related instances.
**Arguments**:
- `rel (Model)`: Model to follow
- `follow (bool)`: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
- `visited (Set)`: internal parameter for recursive calls - already visited models
- `update_count (int)`: internal parameter for recursive calls -
number of updated instances
**Returns**:
`(Tuple[int, Set])`: tuple of update count and visited
<a name="models.model.Model.update"></a>
#### update
```python
| async update(**kwargs: Any) -> "Model"
| async update(_columns: List[str] = None, **kwargs: Any) -> T
```
Performs update of Model instance in the database.
@ -129,14 +108,15 @@ Sends pre_update and post_update signals.
Sets model save status to True.
**Arguments**:
- `_columns (List)`: list of columns to update, if None all are updated
- `kwargs (Any)`: list of fields to update as field=value pairs
**Raises**:
- `ModelPersistenceError`: If the pk column is not set
**Arguments**:
- `kwargs (Any)`: list of fields to update as field=value pairs
**Returns**:
`(Model)`: updated Model
@ -166,7 +146,7 @@ or update and the Model will be saved in database again.
#### load
```python
| async load() -> "Model"
| async load() -> T
```
Allow to refresh existing Models fields from database.
@ -185,7 +165,7 @@ Does NOT refresh the related models fields if they were loaded before.
#### load\_all
```python
| async load_all(follow: bool = False, exclude: Union[List, str, Set, Dict] = None) -> "Model"
| async load_all(follow: bool = False, exclude: Union[List, str, Set, Dict] = None, order_by: Union[List, str] = None) -> T
```
Allow to refresh existing Models fields from database.
@ -203,17 +183,18 @@ 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.
**Raises**:
- `NoMatch`: If given pk is not found in database.
**Arguments**:
- `exclude ()`:
- `order_by (Union[List, str])`: columns by which models should be sorted
- `exclude (Union[List, str, Set, Dict])`: related models to exclude
- `follow (bool)`: flag to trigger deep save -
by default only directly related models are saved
with follow=True also related models of related models are saved
**Raises**:
- `NoMatch`: If given pk is not found in database.
**Returns**:
`(Model)`: reloaded Model

View File

@ -364,7 +364,7 @@ Returns related field names applying on them include and exclude set.
```python
| @staticmethod
| _extract_nested_models_from_list(models: MutableSequence, include: Union[Set, Dict, None], exclude: Union[Set, Dict, None]) -> List
| _extract_nested_models_from_list(relation_map: Dict, models: MutableSequence, include: Union[Set, Dict, None], exclude: Union[Set, Dict, None]) -> List
```
Converts list of models into list of dictionaries.
@ -383,7 +383,7 @@ Converts list of models into list of dictionaries.
#### \_skip\_ellipsis
```python
| _skip_ellipsis(items: Union[Set, Dict, None], key: str) -> Union[Set, Dict, None]
| _skip_ellipsis(items: Union[Set, Dict, None], key: str, default_return: Any = None) -> Union[Set, Dict, None]
```
Helper to traverse the include/exclude dictionaries.
@ -399,11 +399,25 @@ and not the actual set/dict with fields names.
`(Union[Set, Dict, None])`: nested value of the items
<a name="models.newbasemodel.NewBaseModel._convert_all"></a>
#### \_convert\_all
```python
| _convert_all(items: Union[Set, Dict, None]) -> Union[Set, Dict, None]
```
Helper to convert __all__ pydantic special index to ormar which does not
support index based exclusions.
**Arguments**:
- `items (Union[Set, Dict, None])`: current include/exclude value
<a name="models.newbasemodel.NewBaseModel._extract_nested_models"></a>
#### \_extract\_nested\_models
```python
| _extract_nested_models(nested: bool, dict_instance: Dict, include: Optional[Dict], exclude: Optional[Dict]) -> Dict
| _extract_nested_models(relation_map: Dict, dict_instance: Dict, include: Optional[Dict], exclude: Optional[Dict]) -> Dict
```
Traverse nested models and converts them into dictionaries.
@ -424,7 +438,7 @@ Calls itself recursively if needed.
#### dict
```python
| dict(*, include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None, by_alias: bool = False, skip_defaults: bool = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, nested: bool = False) -> "DictStrAny"
| dict(*, include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None, by_alias: bool = False, skip_defaults: bool = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, relation_map: Dict = None) -> "DictStrAny"
```
Generate a dictionary representation of the model,
@ -443,7 +457,7 @@ Additionally fields decorated with @property_field are also added.
- `exclude_unset (bool)`: flag to exclude not set values - passed to pydantic
- `exclude_defaults (bool)`: flag to exclude default values - passed to pydantic
- `exclude_none (bool)`: flag to exclude None values - passed to pydantic
- `nested (bool)`: flag if the current model is nested
- `relation_map (Dict)`: map of the relations to follow to avoid circural deps
**Returns**:
@ -536,14 +550,14 @@ That includes own non-relational fields ang foreign key fields.
#### get\_relation\_model\_id
```python
| get_relation_model_id(target_field: Type["BaseField"]) -> Optional[int]
| get_relation_model_id(target_field: "BaseField") -> Optional[int]
```
Returns an id of the relation side model to use in prefetch query.
**Arguments**:
- `target_field (Type["BaseField"])`: field with relation definition
- `target_field ("BaseField")`: field with relation definition
**Returns**:

View File

@ -0,0 +1,78 @@
<a name="models.traversible"></a>
# models.traversible
<a name="models.traversible.NodeList"></a>
## NodeList Objects
```python
class NodeList()
```
Helper class that helps with iterating nested models
<a name="models.traversible.NodeList.add"></a>
#### add
```python
| add(node_class: Type["RelationMixin"], relation_name: str = None, parent_node: "Node" = None) -> "Node"
```
Adds new Node or returns the existing one
**Arguments**:
- `node_class (ormar.models.metaclass.ModelMetaclass)`: Model in current node
- `relation_name (str)`: name of the current relation
- `parent_node (Optional[Node])`: parent node
**Returns**:
`(Node)`: returns new or already existing node
<a name="models.traversible.NodeList.find"></a>
#### find
```python
| find(node_class: Type["RelationMixin"], relation_name: Optional[str] = None, parent_node: "Node" = None) -> Optional["Node"]
```
Searches for existing node with given parameters
**Arguments**:
- `node_class (ormar.models.metaclass.ModelMetaclass)`: Model in current node
- `relation_name (str)`: name of the current relation
- `parent_node (Optional[Node])`: parent node
**Returns**:
`(Optional[Node])`: returns already existing node or None
<a name="models.traversible.Node"></a>
## Node Objects
```python
class Node()
```
<a name="models.traversible.Node.visited"></a>
#### visited
```python
| visited(relation_name: str) -> bool
```
Checks if given relation was already visited.
Relation was visited if it's name is in current node children.
Relation was visited if one of the parent node had the same Model class
**Arguments**:
- `relation_name (str)`: name of relation
**Returns**:
`(bool)`: result of the check