Skip to content

validation

check_if_field_has_choices(field)

Checks if given field has choices populated. A if it has one, a validator for this field needs to be attached.

Parameters:

Name Type Description Default
field BaseField

ormar field to check

required

Returns:

Type Description
bool

result of the check

Source code in ormar/models/helpers/validation.py
33
34
35
36
37
38
39
40
41
42
43
def check_if_field_has_choices(field: "BaseField") -> bool:
    """
    Checks if given field has choices populated.
    A if it has one, a validator for this field needs to be attached.

    :param field: ormar field to check
    :type field: BaseField
    :return: result of the check
    :rtype: bool
    """
    return hasattr(field, "choices") and bool(field.choices)

construct_modify_schema_function(fields_with_choices)

Modifies the schema to include fields with choices validator. Those fields will be displayed in schema as Enum types with available choices values listed next to them.

Note that schema extra has to be a function, otherwise it's called to soon before all the relations are expanded.

Parameters:

Name Type Description Default
fields_with_choices List

list of fields with choices validation

required

Returns:

Type Description
Callable

callable that will be run by pydantic to modify the schema

Source code in ormar/models/helpers/validation.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def construct_modify_schema_function(fields_with_choices: List) -> Callable:
    """
    Modifies the schema to include fields with choices validator.
    Those fields will be displayed in schema as Enum types with available choices
    values listed next to them.

    Note that schema extra has to be a function, otherwise it's called to soon
    before all the relations are expanded.

    :param fields_with_choices: list of fields with choices validation
    :type fields_with_choices: List
    :return: callable that will be run by pydantic to modify the schema
    :rtype: Callable
    """

    def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None:
        for field_id, prop in schema.get("properties", {}).items():
            if field_id in fields_with_choices:
                prop["enum"] = list(model.Meta.model_fields[field_id].choices)
                prop["description"] = prop.get("description", "") + "An enumeration."
        overwrite_example_and_description(schema=schema, model=model)
        overwrite_binary_format(schema=schema, model=model)

    return staticmethod(schema_extra)  # type: ignore

construct_schema_function_without_choices()

Modifies model example and description if needed.

Note that schema extra has to be a function, otherwise it's called to soon before all the relations are expanded.

Returns:

Type Description
Callable

callable that will be run by pydantic to modify the schema

Source code in ormar/models/helpers/validation.py
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def construct_schema_function_without_choices() -> Callable:
    """
    Modifies model example and description if needed.

    Note that schema extra has to be a function, otherwise it's called to soon
    before all the relations are expanded.

    :return: callable that will be run by pydantic to modify the schema
    :rtype: Callable
    """

    def schema_extra(schema: Dict[str, Any], model: Type["Model"]) -> None:
        overwrite_example_and_description(schema=schema, model=model)
        overwrite_binary_format(schema=schema, model=model)

    return staticmethod(schema_extra)  # type: ignore

convert_value_if_needed(field, value)

Converts dates to isoformat as fastapi can check this condition in routes and the fields are not yet parsed. Converts enums to list of it's values. Converts uuids to strings. Converts decimal to float with given scale.

Parameters:

Name Type Description Default
field BaseField

ormar field to check with choices

required
value Any

current values of the model to verify

required

Returns:

Type Description
Any

value, choices list

Source code in ormar/models/helpers/validation.py
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
def convert_value_if_needed(field: "BaseField", value: Any) -> Any:
    """
    Converts dates to isoformat as fastapi can check this condition in routes
    and the fields are not yet parsed.
    Converts enums to list of it's values.
    Converts uuids to strings.
    Converts decimal to float with given scale.

    :param field: ormar field to check with choices
    :type field: BaseField
    :param value: current values of the model to verify
    :type value: Any
    :return: value, choices list
    :rtype: Any
    """
    encoder = ormar.ENCODERS_MAP.get(field.__type__, lambda x: x)
    if field.__type__ == decimal.Decimal:
        precision = field.scale  # type: ignore
        value = encoder(value, precision)
    elif field.__type__ == bytes:
        represent_as_string = field.represent_as_base64_str
        value = encoder(value, represent_as_string)
    elif encoder:
        value = encoder(value)
    return value

generate_model_example(model, relation_map=None)

Generates example to be included in schema in fastapi.

Parameters:

Name Type Description Default
model Type[Model]

ormar.Model

required
relation_map Dict

dict with relations to follow

None

Returns:

Type Description
Dict[str, int]

dict with example values

Source code in ormar/models/helpers/validation.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
def generate_model_example(model: Type["Model"], relation_map: Dict = None) -> Dict:
    """
    Generates example to be included in schema in fastapi.

    :param model: ormar.Model
    :type model: Type["Model"]
    :param relation_map: dict with relations to follow
    :type relation_map: Optional[Dict]
    :return: dict with example values
    :rtype: Dict[str, int]
    """
    example: Dict[str, Any] = dict()
    relation_map = (
        relation_map
        if relation_map is not None
        else translate_list_to_dict(model._iterate_related_models())
    )
    for name, field in model.Meta.model_fields.items():
        populates_sample_fields_values(
            example=example, name=name, field=field, relation_map=relation_map
        )
    to_exclude = {name for name in model.Meta.model_fields}
    pydantic_repr = generate_pydantic_example(pydantic_model=model, exclude=to_exclude)
    example.update(pydantic_repr)

    return example

generate_pydantic_example(pydantic_model, exclude=None)

Generates dict with example.

Parameters:

Name Type Description Default
pydantic_model Type[pydantic.BaseModel]

model to parse

required
exclude Set

list of fields to exclude

None

Returns:

Type Description
Dict

dict with fields and sample values

Source code in ormar/models/helpers/validation.py
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def generate_pydantic_example(
    pydantic_model: Type[pydantic.BaseModel], exclude: Set = None
) -> Dict:
    """
    Generates dict with example.

    :param pydantic_model: model to parse
    :type pydantic_model: Type[pydantic.BaseModel]
    :param exclude: list of fields to exclude
    :type exclude: Optional[Set]
    :return: dict with fields and sample values
    :rtype: Dict
    """
    example: Dict[str, Any] = dict()
    exclude = exclude or set()
    name_to_check = [name for name in pydantic_model.__fields__ if name not in exclude]
    for name in name_to_check:
        field = pydantic_model.__fields__[name]
        type_ = field.type_
        if field.shape == SHAPE_LIST:
            example[name] = [get_pydantic_example_repr(type_)]
        else:
            example[name] = get_pydantic_example_repr(type_)
    return example

get_nested_model_example(name, field, relation_map)

Gets representation of nested model.

Parameters:

Name Type Description Default
name str

name of the field to follow

required
field BaseField

ormar field

required
relation_map Dict

dict with relation map

required

Returns:

Type Description
Union[List, Dict]

nested model or list of nested model repr

Source code in ormar/models/helpers/validation.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def get_nested_model_example(
    name: str, field: "BaseField", relation_map: Dict
) -> Union[List, Dict]:
    """
    Gets representation of nested model.

    :param name: name of the field to follow
    :type name: str
    :param field: ormar field
    :type field: BaseField
    :param relation_map: dict with relation map
    :type relation_map: Dict
    :return: nested model or list of nested model repr
    :rtype: Union[List, Dict]
    """
    value = generate_model_example(field.to, relation_map=relation_map.get(name, {}))
    new_value: Union[List, Dict] = [value] if field.is_multi or field.virtual else value
    return new_value

get_pydantic_example_repr(type_)

Gets sample representation of pydantic field for example dict.

Parameters:

Name Type Description Default
type_ Any

type of pydantic field

required

Returns:

Type Description
Any

representation to include in example

Source code in ormar/models/helpers/validation.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def get_pydantic_example_repr(type_: Any) -> Any:
    """
    Gets sample representation of pydantic field for example dict.

    :param type_: type of pydantic field
    :type type_: Any
    :return: representation to include in example
    :rtype: Any
    """
    if issubclass(type_, (numbers.Number, decimal.Decimal)):
        return 0
    if issubclass(type_, pydantic.BaseModel):
        return generate_pydantic_example(pydantic_model=type_)
    return "string"

overwrite_binary_format(schema, model)

Overwrites format of the field if it's a LargeBinary field with a flag to represent the field as base64 encoded string.

Parameters:

Name Type Description Default
schema Dict[str, Any]

schema of current model

required
model Type[Model]

model class

required
Source code in ormar/models/helpers/validation.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
def overwrite_binary_format(schema: Dict[str, Any], model: Type["Model"]) -> None:
    """
    Overwrites format of the field if it's a LargeBinary field with
    a flag to represent the field as base64 encoded string.

    :param schema: schema of current model
    :type schema: Dict[str, Any]
    :param model: model class
    :type model: Type["Model"]
    """
    for field_id, prop in schema.get("properties", {}).items():
        if (
            field_id in model._bytes_fields
            and model.Meta.model_fields[field_id].represent_as_base64_str
        ):
            prop["format"] = "base64"
            if prop.get("enum"):
                prop["enum"] = [
                    base64.b64encode(choice).decode() for choice in prop.get("enum", [])
                ]

overwrite_example_and_description(schema, model)

Overwrites the example with properly nested children models. Overwrites the description if it's taken from ormar.Model.

Parameters:

Name Type Description Default
schema Dict[str, Any]

schema of current model

required
model Type[Model]

model class

required
Source code in ormar/models/helpers/validation.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def overwrite_example_and_description(
    schema: Dict[str, Any], model: Type["Model"]
) -> None:
    """
    Overwrites the example with properly nested children models.
    Overwrites the description if it's taken from ormar.Model.

    :param schema: schema of current model
    :type schema: Dict[str, Any]
    :param model: model class
    :type model: Type["Model"]
    """
    schema["example"] = generate_model_example(model=model)
    if "Main base class of ormar Model." in schema.get("description", ""):
        schema["description"] = f"{model.__name__}"

populate_choices_validators(model)

Checks if Model has any fields with choices set. If yes it adds choices validation into pre root validators.

Parameters:

Name Type Description Default
model Type[Model]

newly constructed Model

required
Source code in ormar/models/helpers/validation.py
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
def populate_choices_validators(model: Type["Model"]) -> None:  # noqa CCR001
    """
    Checks if Model has any fields with choices set.
    If yes it adds choices validation into pre root validators.

    :param model: newly constructed Model
    :type model: Model class
    """
    fields_with_choices = []
    if not meta_field_not_set(model=model, field_name="model_fields"):
        if not hasattr(model, "_choices_fields"):
            model._choices_fields = set()
        for name, field in model.Meta.model_fields.items():
            if check_if_field_has_choices(field) and name not in model._choices_fields:
                fields_with_choices.append(name)
                validator = make_generic_validator(generate_validator(field))
                model.__fields__[name].validators.append(validator)
                model._choices_fields.add(name)

        if fields_with_choices:
            model.Config.schema_extra = construct_modify_schema_function(
                fields_with_choices=fields_with_choices
            )
        else:
            model.Config.schema_extra = construct_schema_function_without_choices()

populates_sample_fields_values(example, name, field, relation_map=None)

Iterates the field and sets fields to sample values

Parameters:

Name Type Description Default
field BaseField

ormar field

required
name str

name of the field

required
example Dict[str, Any]

example dict

required
relation_map Dict

dict with relations to follow

None
Source code in ormar/models/helpers/validation.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
def populates_sample_fields_values(
    example: Dict[str, Any], name: str, field: "BaseField", relation_map: Dict = None
) -> None:
    """
    Iterates the field and sets fields to sample values

    :param field: ormar field
    :type field: BaseField
    :param name: name of the field
    :type name: str
    :param example: example dict
    :type example: Dict[str, Any]
    :param relation_map: dict with relations to follow
    :type relation_map: Optional[Dict]
    """
    if not field.is_relation:
        is_bytes_str = field.__type__ == bytes and field.represent_as_base64_str
        example[name] = field.__sample__ if not is_bytes_str else "string"
    elif isinstance(relation_map, dict) and name in relation_map:
        example[name] = get_nested_model_example(
            name=name, field=field, relation_map=relation_map
        )