Skip to content

models

check_required_meta_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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def check_required_meta_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 not hasattr(new_model.Meta, "database"):
        if not getattr(new_model.Meta, "abstract", False):
            raise ormar.ModelDefinitionError(
                f"{new_model.__name__} does not have database defined."
            )

    else:
        substitue_backend_pool_for_sqlite(new_model=new_model)

    if not hasattr(new_model.Meta, "metadata"):
        if not getattr(new_model.Meta, "abstract", False):
            raise ormar.ModelDefinitionError(
                f"{new_model.__name__} does not have metadata defined."
            )

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
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
16
17
18
19
20
21
22
23
24
25
26
27
28
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
    )

meta_field_not_set(model, field_name)

Checks if field with given name is already present in model.Meta. 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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
def meta_field_not_set(model: Type["Model"], field_name: str) -> bool:
    """
    Checks if field with given name is already present in model.Meta.
    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 hasattr(model.Meta, field_name) or not getattr(model.Meta, field_name)

populate_default_options_values(new_model, model_fields)

Sets all optional Meta values to it's 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
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def populate_default_options_values(  # noqa: CCR001
    new_model: Type["Model"], model_fields: Dict
) -> None:
    """
    Sets all optional Meta values to it's 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]
    """
    defaults = {
        "queryset_class": ormar.QuerySet,
        "constraints": [],
        "model_fields": model_fields,
        "abstract": False,
        "extra": Extra.forbid,
        "orders_by": [],
        "exclude_parent_fields": [],
    }
    for key, value in defaults.items():
        if not hasattr(new_model.Meta, key):
            setattr(new_model.Meta, key, value)

    if any(
        is_field_an_forward_ref(field) for field in new_model.Meta.model_fields.values()
    ):
        new_model.Meta.requires_ref_update = True
    else:
        new_model.Meta.requires_ref_update = False

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

    new_model.__relation_map__ = 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
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
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.Meta.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)