Skip to content

models

check_required_config_parameters(new_model)

Verifies if ormar.Model has database and metadata set.

Recreates Connection pool for sqlite3

Parameters:

Name Type Description Default
new_model Type[Model]

newly declared ormar Model

required
Source code in ormar\models\helpers\models.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def check_required_config_parameters(new_model: Type["Model"]) -> None:
    """
    Verifies if ormar.Model has database and metadata set.

    Recreates Connection pool for sqlite3

    :param new_model: newly declared ormar Model
    :type new_model: Model class
    """
    if new_model.ormar_config.database is None and not new_model.ormar_config.abstract:
        raise ormar.ModelDefinitionError(
            f"{new_model.__name__} does not have database defined."
        )
    elif not new_model.ormar_config.abstract:
        substitue_backend_pool_for_sqlite(new_model=new_model)

    if new_model.ormar_config.metadata is None and not new_model.ormar_config.abstract:
        raise ormar.ModelDefinitionError(
            f"{new_model.__name__} does not have metadata defined."
        )

config_field_not_set(model, field_name)

Checks if field with given name is already present in model.OrmarConfig. Then check if it's set to something truthful (in practice meaning not None, as it's non or ormar Field only).

Parameters:

Name Type Description Default
model Type[Model]

newly constructed model

required
field_name str

name of the ormar field

required

Returns:

Type Description
bool

result of the check

Source code in ormar\models\helpers\models.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def config_field_not_set(model: Type["Model"], field_name: str) -> bool:
    """
    Checks if field with given name is already present in model.OrmarConfig.
    Then check if it's set to something truthful
    (in practice meaning not None, as it's non or ormar Field only).

    :param model: newly constructed model
    :type model: Model class
    :param field_name: name of the ormar field
    :type field_name: str
    :return: result of the check
    :rtype: bool
    """
    return not getattr(model.ormar_config, field_name)

extract_annotations_and_default_vals(attrs)

Extracts annotations from class namespace dict and triggers extraction of ormar model_fields.

Parameters:

Name Type Description Default
attrs Dict

namespace of the class created

required

Returns:

Type Description
Tuple[Dict, Dict]

namespace of the class updated, dict of extracted model_fields

Source code in ormar\models\helpers\models.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def extract_annotations_and_default_vals(attrs: Dict) -> Tuple[Dict, Dict]:
    """
    Extracts annotations from class namespace dict and triggers
    extraction of ormar model_fields.

    :param attrs: namespace of the class created
    :type attrs: Dict
    :return: namespace of the class updated, dict of extracted model_fields
    :rtype: Tuple[Dict, Dict]
    """
    key = "__annotations__"
    attrs[key] = attrs.get(key, {})
    attrs, model_fields = populate_pydantic_default_values(attrs)
    return attrs, model_fields

Translates the list of related strings into a dictionary. That way nested models are grouped to traverse them in a right order and to avoid repetition.

Sample: ["people__houses", "people__cars__models", "people__cars__colors"] will become: {'people': {'houses': [], 'cars': ['models', 'colors']}}

Result dictionary is sorted by length of the values and by key

Parameters:

Name Type Description Default
list_ List

list of related models used in select related

required

Returns:

Type Description
Dict[str, List]

list converted to dictionary to avoid repetition and group nested models

Source code in ormar\models\helpers\models.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def group_related_list(list_: List) -> Dict:
    """
    Translates the list of related strings into a dictionary.
    That way nested models are grouped to traverse them in a right order
    and to avoid repetition.

    Sample: ["people__houses", "people__cars__models", "people__cars__colors"]
    will become:
    {'people': {'houses': [], 'cars': ['models', 'colors']}}

    Result dictionary is sorted by length of the values and by key

    :param list_: list of related models used in select related
    :type list_: List[str]
    :return: list converted to dictionary to avoid repetition and group nested models
    :rtype: Dict[str, List]
    """
    result_dict: Dict[str, Any] = dict()
    list_.sort(key=lambda x: x.split("__")[0])
    grouped = itertools.groupby(list_, key=lambda x: x.split("__")[0])
    for key, group in grouped:
        group_list = list(group)
        new = sorted(
            ["__".join(x.split("__")[1:]) for x in group_list if len(x.split("__")) > 1]
        )
        if any("__" in x for x in new):
            result_dict[key] = group_related_list(new)
        else:
            result_dict.setdefault(key, []).extend(new)
    return dict(sorted(result_dict.items(), key=lambda item: len(item[1])))

is_field_an_forward_ref(field)

Checks if field is a relation field and whether any of the referenced models are ForwardRefs that needs to be updated before proceeding.

Parameters:

Name Type Description Default
field BaseField

model field to verify

required

Returns:

Type Description
bool

result of the check

Source code in ormar\models\helpers\models.py
15
16
17
18
19
20
21
22
23
24
25
26
27
def is_field_an_forward_ref(field: "BaseField") -> bool:
    """
    Checks if field is a relation field and whether any of the referenced models
    are ForwardRefs that needs to be updated before proceeding.

    :param field: model field to verify
    :type field: Type[BaseField]
    :return: result of the check
    :rtype: bool
    """
    return field.is_relation and (
        field.to.__class__ == ForwardRef or field.through.__class__ == ForwardRef
    )

populate_default_options_values(new_model, model_fields)

Sets all optional OrmarConfig values to its defaults and set model_fields that were already previously extracted.

Here should live all options that are not overwritten/set for all models.

Current options are: * constraints = [] * abstract = False

Parameters:

Name Type Description Default
new_model Type[Model]

newly constructed Model

required
model_fields Dict

dict of model fields

required
Source code in ormar\models\helpers\models.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def populate_default_options_values(  # noqa: CCR001
    new_model: Type["Model"], model_fields: Dict
) -> None:
    """
    Sets all optional OrmarConfig values to its defaults
    and set model_fields that were already previously extracted.

    Here should live all options that are not overwritten/set for all models.

    Current options are:
    * constraints = []
    * abstract = False

    :param new_model: newly constructed Model
    :type new_model: Model class
    :param model_fields: dict of model fields
    :type model_fields: Union[Dict[str, type], Dict]
    """
    new_model.ormar_config.model_fields.update(model_fields)
    if any(is_field_an_forward_ref(field) for field in model_fields.values()):
        new_model.ormar_config.requires_ref_update = True

    new_model._json_fields = {
        name for name, field in model_fields.items() if field.__type__ == pydantic.Json
    }
    new_model._bytes_fields = {
        name for name, field in model_fields.items() if field.__type__ == bytes
    }

    new_model.__relation_map__ = None
    new_model.__ormar_fields_validators__ = None

substitue_backend_pool_for_sqlite(new_model)

Recreates Connection pool for sqlite3 with new factory that executes "PRAGMA foreign_keys=1; on initialization to enable foreign keys.

Parameters:

Name Type Description Default
new_model Type[Model]

newly declared ormar Model

required
Source code in ormar\models\helpers\models.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def substitue_backend_pool_for_sqlite(new_model: Type["Model"]) -> None:
    """
    Recreates Connection pool for sqlite3 with new factory that
    executes "PRAGMA foreign_keys=1; on initialization to enable foreign keys.

    :param new_model: newly declared ormar Model
    :type new_model: Model class
    """
    backend = new_model.ormar_config.database._backend
    if (
        backend._dialect.name == "sqlite" and "factory" not in backend._options
    ):  # pragma: no cover
        backend._options["factory"] = Connection
        old_pool = backend._pool
        backend._pool = old_pool.__class__(backend._database_url, **backend._options)