Skip to content

helpers

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)

expand_reverse_relationships(model)

Iterates through model_fields of given model and verifies if all reverse relation have been populated on related models.

If the reverse relation has not been set before it's set here.

Parameters:

Name Type Description Default
model Type[Model]

model on which relation should be checked and registered

required
Source code in ormar\models\helpers\relations.py
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def expand_reverse_relationships(model: Type["Model"]) -> None:
    """
    Iterates through model_fields of given model and verifies if all reverse
    relation have been populated on related models.

    If the reverse relation has not been set before it's set here.

    :param model: model on which relation should be checked and registered
    :type model: Model class
    """
    model_fields = list(model.ormar_config.model_fields.values())
    for model_field in model_fields:
        if model_field.is_relation and not model_field.has_unresolved_forward_refs():
            model_field = cast("ForeignKeyField", model_field)
            expand_reverse_relationship(model_field=model_field)

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

get_potential_fields(attrs)

Gets all the fields in current class namespace that are Fields.

Parameters:

Name Type Description Default
attrs Union[Dict, MappingProxyType]

current class namespace

required

Returns:

Type Description
Dict

extracted fields that are ormar Fields

Source code in ormar\models\helpers\pydantic.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def get_potential_fields(attrs: Union[Dict, MappingProxyType]) -> Dict:
    """
    Gets all the fields in current class namespace that are Fields.

    :param attrs: current class namespace
    :type attrs: Dict
    :return: extracted fields that are ormar Fields
    :rtype: Dict
    """
    return {
        k: v
        for k, v in attrs.items()
        if (
            (isinstance(v, type) and issubclass(v, BaseField))
            or isinstance(v, BaseField)
        )
    }

get_pydantic_base_orm_config()

Returns empty pydantic Config with orm_mode set to True.

Returns:

Type Description
pydantic Config

empty default config with orm_mode set.

Source code in ormar\models\helpers\pydantic.py
 98
 99
100
101
102
103
104
105
106
def get_pydantic_base_orm_config() -> pydantic.ConfigDict:
    """
    Returns empty pydantic Config with orm_mode set to True.

    :return: empty default config with orm_mode set.
    :rtype: pydantic Config
    """

    return ConfigDict(validate_assignment=True, ser_json_bytes="base64")

merge_or_generate_pydantic_config(attrs, name)

Checks if the user provided pydantic Config, and if he did merges it with the default one.

Updates the attrs in place with a new config.

Source code in ormar\models\helpers\pydantic.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def merge_or_generate_pydantic_config(attrs: Dict, name: str) -> None:
    """
    Checks if the user provided pydantic Config,
    and if he did merges it with the default one.

    Updates the attrs in place with a new config.

    :rtype: None
    """
    default_config = get_pydantic_base_orm_config()
    if "model_config" in attrs:
        provided_config = attrs["model_config"]
        if not isinstance(provided_config, dict):
            raise ModelDefinitionError(
                f"Config provided for class {name} has to be a dictionary."
            )

        config = {**default_config, **provided_config}
        attrs["model_config"] = config
    else:
        attrs["model_config"] = default_config

modify_schema_example(model)

Modifies the schema example in openapi schema.

Parameters:

Name Type Description Default
model Type[Model]

newly constructed Model

required
Source code in ormar\models\helpers\validation.py
222
223
224
225
226
227
228
229
230
def modify_schema_example(model: Type["Model"]) -> None:  # noqa CCR001
    """
    Modifies the schema example in openapi schema.

    :param model: newly constructed Model
    :type model: Model class
    """
    if not config_field_not_set(model=model, field_name="model_fields"):
        model.model_config["json_schema_extra"] = construct_schema_function()

populate_config_sqlalchemy_table_if_required(config)

Constructs sqlalchemy table out of columns and parameters set on OrmarConfig. It populates name, metadata, columns and constraints.

Parameters:

Name Type Description Default
config OrmarConfig

OrmarConfig of the Model without sqlalchemy table constructed

required
Source code in ormar\models\helpers\sqlalchemy.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
def populate_config_sqlalchemy_table_if_required(config: "OrmarConfig") -> None:
    """
    Constructs sqlalchemy table out of columns and parameters set on OrmarConfig.
    It populates name, metadata, columns and constraints.

    :param config: OrmarConfig of the Model without sqlalchemy table constructed
    :type config: Model class OrmarConfig
    """
    if config.table is None and check_for_null_type_columns_from_forward_refs(
        config=config
    ):
        set_constraint_names(config=config)
        table = sqlalchemy.Table(
            config.tablename, config.metadata, *config.columns, *config.constraints
        )
        config.table = table

populate_config_tablename_columns_and_pk(name, new_model)

Sets Model tablename if it's not already set in OrmarConfig. Default tablename if not present is class name lower + s (i.e. Bed becomes -> beds)

Checks if Model's OrmarConfig have pkname and columns set. If not calls the sqlalchemy_columns_from_model_fields to populate columns from ormar.fields definitions.

Parameters:

Name Type Description Default
name str

name of the current Model

required
new_model Type[Model]

currently constructed Model

required

Returns:

Type Description
ormar.models.metaclass.ModelMetaclass

Model with populated pkname and columns in OrmarConfig

Raises:

Type Description
ModelDefinitionError

if pkname is not present raises ModelDefinitionError. Each model has to have pk.

Source code in ormar\models\helpers\sqlalchemy.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def populate_config_tablename_columns_and_pk(
    name: str, new_model: Type["Model"]
) -> Type["Model"]:
    """
    Sets Model tablename if it's not already set in OrmarConfig.
    Default tablename if not present is class name lower + s (i.e. Bed becomes -> beds)

    Checks if Model's OrmarConfig have pkname and columns set.
    If not calls the sqlalchemy_columns_from_model_fields to populate
    columns from ormar.fields definitions.

    :raises ModelDefinitionError: if pkname is not present raises ModelDefinitionError.
    Each model has to have pk.

    :param name: name of the current Model
    :type name: str
    :param new_model: currently constructed Model
    :type new_model: ormar.models.metaclass.ModelMetaclass
    :return: Model with populated pkname and columns in OrmarConfig
    :rtype: ormar.models.metaclass.ModelMetaclass
    """
    tablename = name.lower() + "s"
    new_model.ormar_config.tablename = (
        new_model.ormar_config.tablename
        if new_model.ormar_config.tablename
        else tablename
    )
    pkname: Optional[str]

    if new_model.ormar_config.columns:
        columns = new_model.ormar_config.columns
        pkname = new_model.ormar_config.pkname
    else:
        pkname, columns = sqlalchemy_columns_from_model_fields(
            new_model.ormar_config.model_fields, new_model
        )

    if pkname is None:
        raise ormar.ModelDefinitionError("Table has to have a primary key.")

    new_model.ormar_config.columns = columns
    new_model.ormar_config.pkname = pkname
    if not new_model.ormar_config.orders_by:
        # by default, we sort by pk name if other option not provided
        new_model.ormar_config.orders_by.append(pkname)
    return new_model

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

register_relation_in_alias_manager(field)

Registers the relation (and reverse relation) in alias manager. The m2m relations require registration of through model between actual end models of the relation.

Delegates the actual registration to: m2m - register_many_to_many_relation_on_build fk - register_relation_on_build

Parameters:

Name Type Description Default
field ForeignKeyField

relation field

required
Source code in ormar\models\helpers\relations.py
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
def register_relation_in_alias_manager(field: "ForeignKeyField") -> None:
    """
    Registers the relation (and reverse relation) in alias manager.
    The m2m relations require registration of through model between
    actual end models of the relation.

    Delegates the actual registration to:
    m2m - register_many_to_many_relation_on_build
    fk - register_relation_on_build

    :param field: relation field
    :type field: ForeignKey or ManyToManyField class
    """
    if field.is_multi:
        if field.has_unresolved_forward_refs():
            return
        field = cast("ManyToManyField", field)
        register_many_to_many_relation_on_build(field=field)
    elif field.is_relation and not field.is_through:
        if field.has_unresolved_forward_refs():
            return
        register_relation_on_build(field=field)

remove_excluded_parent_fields(model)

Removes pydantic fields that should be excluded from parent models

Parameters:

Name Type Description Default
model Type[Model]
required
Source code in ormar\models\helpers\pydantic.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def remove_excluded_parent_fields(model: Type["Model"]) -> None:
    """
    Removes pydantic fields that should be excluded from parent models

    :param model:
    :type model: Type["Model"]
    """
    excludes = {*model.ormar_config.exclude_parent_fields} - {
        *model.ormar_config.model_fields.keys()
    }
    if excludes:
        model.model_fields = {
            k: v for k, v in model.model_fields.items() if k not in excludes
        }
        model.model_rebuild(force=True)

sqlalchemy_columns_from_model_fields(model_fields, new_model)

Iterates over declared on Model model fields and extracts fields that should be treated as database fields.

If the model is empty it sets mandatory id field as primary key (used in through models in m2m relations).

Triggers a validation of relation_names in relation fields. If multiple fields are leading to the same related model only one can have empty related_name param. Also related_names have to be unique.

Trigger validation of primary_key - only one and required pk can be set

Sets owner on each model_field as reference to newly created Model.

Parameters:

Name Type Description Default
model_fields Dict

dictionary of declared ormar model fields

required
new_model Type[Model]
required

Returns:

Type Description
Tuple[Optional[str], List[sqlalchemy.Column]]

pkname, list of sqlalchemy columns

Raises:

Type Description
ModelDefinitionError

if validation of related_names fail, or pkname validation fails.

Source code in ormar\models\helpers\sqlalchemy.py
121
122
123
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
154
155
def sqlalchemy_columns_from_model_fields(
    model_fields: Dict, new_model: Type["Model"]
) -> Tuple[Optional[str], List[sqlalchemy.Column]]:
    """
    Iterates over declared on Model model fields and extracts fields that
    should be treated as database fields.

    If the model is empty it sets mandatory id field as primary key
    (used in through models in m2m relations).

    Triggers a validation of relation_names in relation fields. If multiple fields
    are leading to the same related model only one can have empty related_name param.
    Also related_names have to be unique.

    Trigger validation of primary_key - only one and required pk can be set

    Sets `owner` on each model_field as reference to newly created Model.

    :raises ModelDefinitionError: if validation of related_names fail,
    or pkname validation fails.
    :param model_fields: dictionary of declared ormar model fields
    :type model_fields: Dict[str, ormar.Field]
    :param new_model:
    :type new_model: Model class
    :return: pkname, list of sqlalchemy columns
    :rtype: Tuple[Optional[str], List[sqlalchemy.Column]]
    """
    if len(model_fields.keys()) == 0:
        model_fields["id"] = ormar.Integer(name="id", primary_key=True)
        logging.warning(
            f"Table {new_model.ormar_config.tablename} had no fields so auto "
            "Integer primary key named `id` created."
        )
    validate_related_names_in_relations(model_fields, new_model)
    return _process_fields(model_fields=model_fields, new_model=new_model)