Skip to content

ormar

The ormar package is an async mini ORM for Python, with support for Postgres, MySQL, and SQLite.

The main benefit of using ormar are:

  • getting an async ORM that can be used with async frameworks (fastapi, starlette etc.)
  • getting just one model to maintain - you don't have to maintain pydantic and other orm model (sqlalchemy, peewee, gino etc.)

The goal was to create a simple ORM that can be used directly (as request and response models) with fastapi that bases it's data validation on pydantic.

Ormar - apart form obvious ORM in name - get it's name from ormar in swedish which means snakes, and ormar(e) in italian which means cabinet.

And what's a better name for python ORM than snakes cabinet :)

BaseField

Bases: FieldInfo

BaseField serves as a parent class for all basic Fields in ormar. It keeps all common parameters available for all fields as well as set of useful functions.

All values are kept as class variables, ormar Fields are never instantiated. Subclasses pydantic.FieldInfo to keep the fields related to pydantic field types like ConstrainedStr

Source code in ormar/fields/base.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 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
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
class BaseField(FieldInfo):
    """
    BaseField serves as a parent class for all basic Fields in ormar.
    It keeps all common parameters available for all fields as well as
    set of useful functions.

    All values are kept as class variables, ormar Fields are never instantiated.
    Subclasses pydantic.FieldInfo to keep the fields related
    to pydantic field types like ConstrainedStr
    """

    def __init__(self, **kwargs: Any) -> None:
        self.__type__: type = kwargs.pop("__type__", None)
        self.__pydantic_type__: type = kwargs.pop("__pydantic_type__", None)
        self.__sample__: type = kwargs.pop("__sample__", None)
        self.related_name = kwargs.pop("related_name", None)

        self.column_type: sqlalchemy.Column = kwargs.pop("column_type", None)
        self.constraints: List = kwargs.pop("constraints", list())
        self.name: str = kwargs.pop("name", None)
        self.db_alias: str = kwargs.pop("alias", None)

        self.primary_key: bool = kwargs.pop("primary_key", False)
        self.autoincrement: bool = kwargs.pop("autoincrement", False)
        self.nullable: bool = kwargs.pop("nullable", False)
        self.sql_nullable: bool = kwargs.pop("sql_nullable", False)
        self.index: bool = kwargs.pop("index", False)
        self.unique: bool = kwargs.pop("unique", False)
        self.pydantic_only: bool = kwargs.pop("pydantic_only", False)
        if self.pydantic_only:
            warnings.warn(
                "Parameter `pydantic_only` is deprecated and will "
                "be removed in one of the next releases.\n You can declare "
                "pydantic fields in a normal way. \n Check documentation: "
                "https://collerek.github.io/ormar/fields/pydantic-fields",
                DeprecationWarning,
            )
        self.choices: typing.Sequence = kwargs.pop("choices", False)

        self.virtual: bool = kwargs.pop(
            "virtual", None
        )  # ManyToManyFields and reverse ForeignKeyFields
        self.is_multi: bool = kwargs.pop("is_multi", None)  # ManyToManyField
        self.is_relation: bool = kwargs.pop(
            "is_relation", None
        )  # ForeignKeyField + subclasses
        self.is_through: bool = kwargs.pop("is_through", False)  # ThroughFields

        self.through_relation_name = kwargs.pop("through_relation_name", None)
        self.through_reverse_relation_name = kwargs.pop(
            "through_reverse_relation_name", None
        )

        self.skip_reverse: bool = kwargs.pop("skip_reverse", False)
        self.skip_field: bool = kwargs.pop("skip_field", False)

        self.owner: Type["Model"] = kwargs.pop("owner", None)
        self.to: Type["Model"] = kwargs.pop("to", None)
        self.through: Type["Model"] = kwargs.pop("through", None)
        self.self_reference: bool = kwargs.pop("self_reference", False)
        self.self_reference_primary: Optional[str] = kwargs.pop(
            "self_reference_primary", None
        )
        self.orders_by: Optional[List[str]] = kwargs.pop("orders_by", None)
        self.related_orders_by: Optional[List[str]] = kwargs.pop(
            "related_orders_by", None
        )

        self.encrypt_secret: str = kwargs.pop("encrypt_secret", None)
        self.encrypt_backend: EncryptBackends = kwargs.pop(
            "encrypt_backend", EncryptBackends.NONE
        )
        self.encrypt_custom_backend: Optional[Type[EncryptBackend]] = kwargs.pop(
            "encrypt_custom_backend", None
        )

        self.ormar_default: Any = kwargs.pop("default", None)
        self.server_default: Any = kwargs.pop("server_default", None)

        self.comment: str = kwargs.pop("comment", None)

        self.represent_as_base64_str: bool = kwargs.pop(
            "represent_as_base64_str", False
        )

        for name, value in kwargs.items():
            setattr(self, name, value)

        kwargs.update(self.get_pydantic_default())
        super().__init__(**kwargs)

    def is_valid_uni_relation(self) -> bool:
        """
        Checks if field is a relation definition but only for ForeignKey relation,
        so excludes ManyToMany fields, as well as virtual ForeignKey
        (second side of FK relation).

        Is used to define if a field is a db ForeignKey column that
        should be saved/populated when dealing with internal/own
        Model columns only.

        :return: result of the check
        :rtype: bool
        """
        return not self.is_multi and not self.virtual

    def get_alias(self) -> str:
        """
        Used to translate Model column names to database column names during db queries.

        :return: returns custom database column name if defined by user,
        otherwise field name in ormar/pydantic
        :rtype: str
        """
        return self.db_alias if self.db_alias else self.name

    def get_pydantic_default(self) -> Dict:
        """
        Generates base pydantic.FieldInfo with only default and optionally
        required to fix pydantic Json field being set to required=False.
        Used in an ormar Model Metaclass.

        :return: instance of base pydantic.FieldInfo
        :rtype: pydantic.FieldInfo
        """
        base = self.default_value()
        if base is None:
            base = dict(default=None) if self.nullable else dict(default=Undefined)
        if self.__type__ == Json and base.get("default") is Undefined:
            base["default"] = Required
        return base

    def default_value(self, use_server: bool = False) -> Optional[Dict]:
        """
        Returns a FieldInfo instance with populated default
        (static) or default_factory (function).
        If the field is a autoincrement primary key the default is None.
        Otherwise field have to has either default, or default_factory populated.

        If all default conditions fail None is returned.

        Used in converting to pydantic FieldInfo.

        :param use_server: flag marking if server_default should be
        treated as default value, default False
        :type use_server: bool
        :return: returns a call to pydantic.Field
        which is returning a FieldInfo instance
        :rtype: Optional[pydantic.FieldInfo]
        """
        if self.is_auto_primary_key():
            return dict(default=None)
        if self.has_default(use_server=use_server):
            default = (
                self.ormar_default
                if self.ormar_default is not None
                else self.server_default
            )
            if callable(default):
                return dict(default_factory=default)
            return dict(default=default)
        return None

    def get_default(self, use_server: bool = False) -> Any:  # noqa CCR001
        """
        Return default value for a field.
        If the field is Callable the function is called and actual result is returned.
        Used to populate default_values for pydantic Model in ormar Model Metaclass.

        :param use_server: flag marking if server_default should be
        treated as default value, default False
        :type use_server: bool
        :return: default value for the field if set, otherwise implicit None
        :rtype: Any
        """
        if self.has_default():
            default = (
                self.ormar_default
                if self.ormar_default is not None
                else (self.server_default if use_server else None)
            )
            if callable(default):  # pragma: no cover
                default = default()
            return default

    def has_default(self, use_server: bool = True) -> bool:
        """
        Checks if the field has default value set.

        :param use_server: flag marking if server_default should be
        treated as default value, default False
        :type use_server: bool
        :return: result of the check if default value is set
        :rtype: bool
        """
        return self.ormar_default is not None or (
            self.server_default is not None and use_server
        )

    def is_auto_primary_key(self) -> bool:
        """
        Checks if field is first a primary key and if it,
        it's than check if it's set to autoincrement.
        Autoincrement primary_key is nullable/optional.

        :return: result of the check for primary key and autoincrement
        :rtype: bool
        """
        if self.primary_key:
            return self.autoincrement
        return False

    def construct_constraints(self) -> List:
        """
        Converts list of ormar constraints into sqlalchemy ForeignKeys.
        Has to be done dynamically as sqlalchemy binds ForeignKey to the table.
        And we need a new ForeignKey for subclasses of current model

        :return: List of sqlalchemy foreign keys - by default one.
        :rtype: List[sqlalchemy.schema.ForeignKey]
        """
        constraints = [
            sqlalchemy.ForeignKey(
                con.reference,
                ondelete=con.ondelete,
                onupdate=con.onupdate,
                name=f"fk_{self.owner.Meta.tablename}_{self.to.Meta.tablename}"
                f"_{self.to.get_column_alias(self.to.Meta.pkname)}_{self.name}",
            )
            for con in self.constraints
        ]
        return constraints

    def get_column(self, name: str) -> sqlalchemy.Column:
        """
        Returns definition of sqlalchemy.Column used in creation of sqlalchemy.Table.
        Populates name, column type constraints, as well as a number of parameters like
        primary_key, index, unique, nullable, default and server_default.

        :param name: name of the db column - used if alias is not set
        :type name: str
        :return: actual definition of the database column as sqlalchemy requires.
        :rtype: sqlalchemy.Column
        """
        if self.encrypt_backend == EncryptBackends.NONE:
            column = sqlalchemy.Column(
                self.db_alias or name,
                self.column_type,
                *self.construct_constraints(),
                primary_key=self.primary_key,
                nullable=self.sql_nullable,
                index=self.index,
                unique=self.unique,
                default=self.ormar_default,
                server_default=self.server_default,
                comment=self.comment,
            )
        else:
            column = self._get_encrypted_column(name=name)
        return column

    def _get_encrypted_column(self, name: str) -> sqlalchemy.Column:
        """
        Returns EncryptedString column type instead of actual column.

        :param name: column name
        :type name: str
        :return: newly defined column
        :rtype:  sqlalchemy.Column
        """
        if self.primary_key or self.is_relation:
            raise ModelDefinitionError(
                "Primary key field and relations fields" "cannot be encrypted!"
            )
        column = sqlalchemy.Column(
            self.db_alias or name,
            EncryptedString(
                _field_type=self,
                encrypt_secret=self.encrypt_secret,
                encrypt_backend=self.encrypt_backend,
                encrypt_custom_backend=self.encrypt_custom_backend,
            ),
            nullable=self.nullable,
            index=self.index,
            unique=self.unique,
            default=self.ormar_default,
            server_default=self.server_default,
        )
        return column

    def expand_relationship(
        self,
        value: Any,
        child: Union["Model", "NewBaseModel"],
        to_register: bool = True,
    ) -> Any:
        """
        Function overwritten for relations, in basic field the value is returned as is.
        For relations the child model is first constructed (if needed),
        registered in relation and returned.
        For relation fields the value can be a pk value (Any type of field),
        dict (from Model) or actual instance/list of a "Model".

        :param value: a Model field value, returned untouched for non relation fields.
        :type value: Any
        :param child: a child Model to register
        :type child: Union["Model", "NewBaseModel"]
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: returns untouched value for normal fields, expands only for relations
        :rtype: Any
        """
        return value

    def set_self_reference_flag(self) -> None:
        """
        Sets `self_reference` to True if field to and owner are same model.
        :return: None
        :rtype: None
        """
        if self.owner is not None and (
            self.owner == self.to or self.owner.Meta == self.to.Meta
        ):
            self.self_reference = True
            self.self_reference_primary = self.name

    def has_unresolved_forward_refs(self) -> bool:
        """
        Verifies if the filed has any ForwardRefs that require updating before the
        model can be used.

        :return: result of the check
        :rtype: bool
        """
        return False

    def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
        """
        Evaluates the ForwardRef to actual Field based on global and local namespaces

        :param globalns: global namespace
        :type globalns: Any
        :param localns: local namespace
        :type localns: Any
        :return: None
        :rtype: None
        """

    def get_related_name(self) -> str:
        """
        Returns name to use for reverse relation.
        It's either set as `related_name` or by default it's owner model. get_name + 's'
        :return: name of the related_name or default related name.
        :rtype: str
        """
        return ""  # pragma: no cover

_get_encrypted_column(name)

Returns EncryptedString column type instead of actual column.

Parameters:

Name Type Description Default
name str

column name

required

Returns:

Type Description
sqlalchemy.Column

newly defined column

Source code in ormar/fields/base.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
def _get_encrypted_column(self, name: str) -> sqlalchemy.Column:
    """
    Returns EncryptedString column type instead of actual column.

    :param name: column name
    :type name: str
    :return: newly defined column
    :rtype:  sqlalchemy.Column
    """
    if self.primary_key or self.is_relation:
        raise ModelDefinitionError(
            "Primary key field and relations fields" "cannot be encrypted!"
        )
    column = sqlalchemy.Column(
        self.db_alias or name,
        EncryptedString(
            _field_type=self,
            encrypt_secret=self.encrypt_secret,
            encrypt_backend=self.encrypt_backend,
            encrypt_custom_backend=self.encrypt_custom_backend,
        ),
        nullable=self.nullable,
        index=self.index,
        unique=self.unique,
        default=self.ormar_default,
        server_default=self.server_default,
    )
    return column

construct_constraints()

Converts list of ormar constraints into sqlalchemy ForeignKeys. Has to be done dynamically as sqlalchemy binds ForeignKey to the table. And we need a new ForeignKey for subclasses of current model

Returns:

Type Description
List[sqlalchemy.schema.ForeignKey]

List of sqlalchemy foreign keys - by default one.

Source code in ormar/fields/base.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
def construct_constraints(self) -> List:
    """
    Converts list of ormar constraints into sqlalchemy ForeignKeys.
    Has to be done dynamically as sqlalchemy binds ForeignKey to the table.
    And we need a new ForeignKey for subclasses of current model

    :return: List of sqlalchemy foreign keys - by default one.
    :rtype: List[sqlalchemy.schema.ForeignKey]
    """
    constraints = [
        sqlalchemy.ForeignKey(
            con.reference,
            ondelete=con.ondelete,
            onupdate=con.onupdate,
            name=f"fk_{self.owner.Meta.tablename}_{self.to.Meta.tablename}"
            f"_{self.to.get_column_alias(self.to.Meta.pkname)}_{self.name}",
        )
        for con in self.constraints
    ]
    return constraints

default_value(use_server=False)

Returns a FieldInfo instance with populated default (static) or default_factory (function). If the field is a autoincrement primary key the default is None. Otherwise field have to has either default, or default_factory populated.

If all default conditions fail None is returned.

Used in converting to pydantic FieldInfo.

Parameters:

Name Type Description Default
use_server bool

flag marking if server_default should be treated as default value, default False

False

Returns:

Type Description
Optional[pydantic.FieldInfo]

returns a call to pydantic.Field which is returning a FieldInfo instance

Source code in ormar/fields/base.py
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def default_value(self, use_server: bool = False) -> Optional[Dict]:
    """
    Returns a FieldInfo instance with populated default
    (static) or default_factory (function).
    If the field is a autoincrement primary key the default is None.
    Otherwise field have to has either default, or default_factory populated.

    If all default conditions fail None is returned.

    Used in converting to pydantic FieldInfo.

    :param use_server: flag marking if server_default should be
    treated as default value, default False
    :type use_server: bool
    :return: returns a call to pydantic.Field
    which is returning a FieldInfo instance
    :rtype: Optional[pydantic.FieldInfo]
    """
    if self.is_auto_primary_key():
        return dict(default=None)
    if self.has_default(use_server=use_server):
        default = (
            self.ormar_default
            if self.ormar_default is not None
            else self.server_default
        )
        if callable(default):
            return dict(default_factory=default)
        return dict(default=default)
    return None

evaluate_forward_ref(globalns, localns)

Evaluates the ForwardRef to actual Field based on global and local namespaces

Parameters:

Name Type Description Default
globalns Any

global namespace

required
localns Any

local namespace

required

Returns:

Type Description
None

None

Source code in ormar/fields/base.py
357
358
359
360
361
362
363
364
365
366
367
def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
    """
    Evaluates the ForwardRef to actual Field based on global and local namespaces

    :param globalns: global namespace
    :type globalns: Any
    :param localns: local namespace
    :type localns: Any
    :return: None
    :rtype: None
    """

expand_relationship(value, child, to_register=True)

Function overwritten for relations, in basic field the value is returned as is. For relations the child model is first constructed (if needed), registered in relation and returned. For relation fields the value can be a pk value (Any type of field), dict (from Model) or actual instance/list of a "Model".

Parameters:

Name Type Description Default
value Any

a Model field value, returned untouched for non relation fields.

required
child Union['Model', 'NewBaseModel']

a child Model to register

required
to_register bool

flag if the relation should be set in RelationshipManager

True

Returns:

Type Description
Any

returns untouched value for normal fields, expands only for relations

Source code in ormar/fields/base.py
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
def expand_relationship(
    self,
    value: Any,
    child: Union["Model", "NewBaseModel"],
    to_register: bool = True,
) -> Any:
    """
    Function overwritten for relations, in basic field the value is returned as is.
    For relations the child model is first constructed (if needed),
    registered in relation and returned.
    For relation fields the value can be a pk value (Any type of field),
    dict (from Model) or actual instance/list of a "Model".

    :param value: a Model field value, returned untouched for non relation fields.
    :type value: Any
    :param child: a child Model to register
    :type child: Union["Model", "NewBaseModel"]
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: returns untouched value for normal fields, expands only for relations
    :rtype: Any
    """
    return value

get_alias()

Used to translate Model column names to database column names during db queries.

Returns:

Type Description
str

returns custom database column name if defined by user, otherwise field name in ormar/pydantic

Source code in ormar/fields/base.py
127
128
129
130
131
132
133
134
135
def get_alias(self) -> str:
    """
    Used to translate Model column names to database column names during db queries.

    :return: returns custom database column name if defined by user,
    otherwise field name in ormar/pydantic
    :rtype: str
    """
    return self.db_alias if self.db_alias else self.name

get_column(name)

Returns definition of sqlalchemy.Column used in creation of sqlalchemy.Table. Populates name, column type constraints, as well as a number of parameters like primary_key, index, unique, nullable, default and server_default.

Parameters:

Name Type Description Default
name str

name of the db column - used if alias is not set

required

Returns:

Type Description
sqlalchemy.Column

actual definition of the database column as sqlalchemy requires.

Source code in ormar/fields/base.py
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def get_column(self, name: str) -> sqlalchemy.Column:
    """
    Returns definition of sqlalchemy.Column used in creation of sqlalchemy.Table.
    Populates name, column type constraints, as well as a number of parameters like
    primary_key, index, unique, nullable, default and server_default.

    :param name: name of the db column - used if alias is not set
    :type name: str
    :return: actual definition of the database column as sqlalchemy requires.
    :rtype: sqlalchemy.Column
    """
    if self.encrypt_backend == EncryptBackends.NONE:
        column = sqlalchemy.Column(
            self.db_alias or name,
            self.column_type,
            *self.construct_constraints(),
            primary_key=self.primary_key,
            nullable=self.sql_nullable,
            index=self.index,
            unique=self.unique,
            default=self.ormar_default,
            server_default=self.server_default,
            comment=self.comment,
        )
    else:
        column = self._get_encrypted_column(name=name)
    return column

get_default(use_server=False)

Return default value for a field. If the field is Callable the function is called and actual result is returned. Used to populate default_values for pydantic Model in ormar Model Metaclass.

Parameters:

Name Type Description Default
use_server bool

flag marking if server_default should be treated as default value, default False

False

Returns:

Type Description
Any

default value for the field if set, otherwise implicit None

Source code in ormar/fields/base.py
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def get_default(self, use_server: bool = False) -> Any:  # noqa CCR001
    """
    Return default value for a field.
    If the field is Callable the function is called and actual result is returned.
    Used to populate default_values for pydantic Model in ormar Model Metaclass.

    :param use_server: flag marking if server_default should be
    treated as default value, default False
    :type use_server: bool
    :return: default value for the field if set, otherwise implicit None
    :rtype: Any
    """
    if self.has_default():
        default = (
            self.ormar_default
            if self.ormar_default is not None
            else (self.server_default if use_server else None)
        )
        if callable(default):  # pragma: no cover
            default = default()
        return default

get_pydantic_default()

Generates base pydantic.FieldInfo with only default and optionally required to fix pydantic Json field being set to required=False. Used in an ormar Model Metaclass.

Returns:

Type Description
pydantic.FieldInfo

instance of base pydantic.FieldInfo

Source code in ormar/fields/base.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
def get_pydantic_default(self) -> Dict:
    """
    Generates base pydantic.FieldInfo with only default and optionally
    required to fix pydantic Json field being set to required=False.
    Used in an ormar Model Metaclass.

    :return: instance of base pydantic.FieldInfo
    :rtype: pydantic.FieldInfo
    """
    base = self.default_value()
    if base is None:
        base = dict(default=None) if self.nullable else dict(default=Undefined)
    if self.__type__ == Json and base.get("default") is Undefined:
        base["default"] = Required
    return base

Returns name to use for reverse relation. It's either set as related_name or by default it's owner model. get_name + 's'

Returns:

Type Description
str

name of the related_name or default related name.

Source code in ormar/fields/base.py
369
370
371
372
373
374
375
376
def get_related_name(self) -> str:
    """
    Returns name to use for reverse relation.
    It's either set as `related_name` or by default it's owner model. get_name + 's'
    :return: name of the related_name or default related name.
    :rtype: str
    """
    return ""  # pragma: no cover

has_default(use_server=True)

Checks if the field has default value set.

Parameters:

Name Type Description Default
use_server bool

flag marking if server_default should be treated as default value, default False

True

Returns:

Type Description
bool

result of the check if default value is set

Source code in ormar/fields/base.py
206
207
208
209
210
211
212
213
214
215
216
217
218
def has_default(self, use_server: bool = True) -> bool:
    """
    Checks if the field has default value set.

    :param use_server: flag marking if server_default should be
    treated as default value, default False
    :type use_server: bool
    :return: result of the check if default value is set
    :rtype: bool
    """
    return self.ormar_default is not None or (
        self.server_default is not None and use_server
    )

has_unresolved_forward_refs()

Verifies if the filed has any ForwardRefs that require updating before the model can be used.

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/base.py
347
348
349
350
351
352
353
354
355
def has_unresolved_forward_refs(self) -> bool:
    """
    Verifies if the filed has any ForwardRefs that require updating before the
    model can be used.

    :return: result of the check
    :rtype: bool
    """
    return False

is_auto_primary_key()

Checks if field is first a primary key and if it, it's than check if it's set to autoincrement. Autoincrement primary_key is nullable/optional.

Returns:

Type Description
bool

result of the check for primary key and autoincrement

Source code in ormar/fields/base.py
220
221
222
223
224
225
226
227
228
229
230
231
def is_auto_primary_key(self) -> bool:
    """
    Checks if field is first a primary key and if it,
    it's than check if it's set to autoincrement.
    Autoincrement primary_key is nullable/optional.

    :return: result of the check for primary key and autoincrement
    :rtype: bool
    """
    if self.primary_key:
        return self.autoincrement
    return False

is_valid_uni_relation()

Checks if field is a relation definition but only for ForeignKey relation, so excludes ManyToMany fields, as well as virtual ForeignKey (second side of FK relation).

Is used to define if a field is a db ForeignKey column that should be saved/populated when dealing with internal/own Model columns only.

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/base.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def is_valid_uni_relation(self) -> bool:
    """
    Checks if field is a relation definition but only for ForeignKey relation,
    so excludes ManyToMany fields, as well as virtual ForeignKey
    (second side of FK relation).

    Is used to define if a field is a db ForeignKey column that
    should be saved/populated when dealing with internal/own
    Model columns only.

    :return: result of the check
    :rtype: bool
    """
    return not self.is_multi and not self.virtual

set_self_reference_flag()

Sets self_reference to True if field to and owner are same model.

Returns:

Type Description
None

None

Source code in ormar/fields/base.py
335
336
337
338
339
340
341
342
343
344
345
def set_self_reference_flag(self) -> None:
    """
    Sets `self_reference` to True if field to and owner are same model.
    :return: None
    :rtype: None
    """
    if self.owner is not None and (
        self.owner == self.to or self.owner.Meta == self.to.Meta
    ):
        self.self_reference = True
        self.self_reference_primary = self.name

BigInteger

Bases: Integer, int

BigInteger field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
class BigInteger(Integer, int):
    """
    BigInteger field factory that construct Field classes and populated their values.
    """

    _type = int
    _sample = 0

    def __new__(  # type: ignore
        cls,
        *,
        minimum: int = None,
        maximum: int = None,
        multiple_of: int = None,
        **kwargs: Any
    ) -> BaseField:
        autoincrement = kwargs.pop("autoincrement", None)
        autoincrement = (
            autoincrement
            if autoincrement is not None
            else kwargs.get("primary_key", False)
        )
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        kwargs["ge"] = kwargs["minimum"]
        kwargs["le"] = kwargs["maximum"]
        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.BigInteger()

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
638
639
640
641
642
643
644
645
646
647
648
649
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.BigInteger()

Boolean

Bases: ModelFieldFactory, int

Boolean field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
class Boolean(ModelFieldFactory, int):
    """
    Boolean field factory that construct Field classes and populated their values.
    """

    _type = bool
    _sample = True

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.Boolean()

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
396
397
398
399
400
401
402
403
404
405
406
407
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.Boolean()

Date

Bases: ModelFieldFactory, datetime.date

Date field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
class Date(ModelFieldFactory, datetime.date):
    """
    Date field factory that construct Field classes and populated their values.
    """

    _type = datetime.date
    _sample = "date"

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.Date()

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
453
454
455
456
457
458
459
460
461
462
463
464
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.Date()

DateTime

Bases: ModelFieldFactory, datetime.datetime

DateTime field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
class DateTime(ModelFieldFactory, datetime.datetime):
    """
    DateTime field factory that construct Field classes and populated their values.
    """

    _type = datetime.datetime
    _sample = "datetime"

    def __new__(  # type: ignore # noqa CFQ002
        cls, *, timezone: bool = False, **kwargs: Any
    ) -> BaseField:  # type: ignore
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.DateTime(timezone=kwargs.get("timezone", False))

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
431
432
433
434
435
436
437
438
439
440
441
442
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.DateTime(timezone=kwargs.get("timezone", False))

Decimal

Bases: ModelFieldFactory, decimal.Decimal

Decimal field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
class Decimal(ModelFieldFactory, decimal.Decimal):
    """
    Decimal field factory that construct Field classes and populated their values.
    """

    _type = decimal.Decimal
    _sample = 0.0

    def __new__(  # type: ignore # noqa CFQ002
        cls,
        *,
        minimum: float = None,
        maximum: float = None,
        multiple_of: int = None,
        precision: int = None,
        scale: int = None,
        max_digits: int = None,
        decimal_places: int = None,
        **kwargs: Any
    ) -> BaseField:
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        kwargs["ge"] = kwargs["minimum"]
        kwargs["le"] = kwargs["maximum"]

        if kwargs.get("max_digits"):
            kwargs["precision"] = kwargs["max_digits"]
        elif kwargs.get("precision"):
            kwargs["max_digits"] = kwargs["precision"]

        if kwargs.get("decimal_places"):
            kwargs["scale"] = kwargs["decimal_places"]
        elif kwargs.get("scale"):
            kwargs["decimal_places"] = kwargs["scale"]

        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        precision = kwargs.get("precision")
        scale = kwargs.get("scale")
        return sqlalchemy.DECIMAL(precision=precision, scale=scale)

    @classmethod
    def validate(cls, **kwargs: Any) -> None:
        """
        Used to validate if all required parameters on a given field type are set.
        :param kwargs: all params passed during construction
        :type kwargs: Any
        """
        precision = kwargs.get("precision")
        scale = kwargs.get("scale")
        if precision is None or precision < 0 or scale is None or scale < 0:
            raise ModelDefinitionError(
                "Parameters scale and precision are required for field Decimal"
            )

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
743
744
745
746
747
748
749
750
751
752
753
754
755
756
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    precision = kwargs.get("precision")
    scale = kwargs.get("scale")
    return sqlalchemy.DECIMAL(precision=precision, scale=scale)

validate(**kwargs) classmethod

Used to validate if all required parameters on a given field type are set.

Parameters:

Name Type Description Default
kwargs Any

all params passed during construction

required
Source code in ormar/fields/model_fields.py
758
759
760
761
762
763
764
765
766
767
768
769
770
@classmethod
def validate(cls, **kwargs: Any) -> None:
    """
    Used to validate if all required parameters on a given field type are set.
    :param kwargs: all params passed during construction
    :type kwargs: Any
    """
    precision = kwargs.get("precision")
    scale = kwargs.get("scale")
    if precision is None or precision < 0 or scale is None or scale < 0:
        raise ModelDefinitionError(
            "Parameters scale and precision are required for field Decimal"
        )

Enum

Bases: ModelFieldFactory

Enum field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
class Enum(ModelFieldFactory):
    """
    Enum field factory that construct Field classes and populated their values.
    """

    _type = E
    _sample = None

    def __new__(  # type: ignore # noqa CFQ002
        cls, *, enum_class: Type[E], **kwargs: Any
    ) -> BaseField:

        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        return super().__new__(cls, **kwargs)

    @classmethod
    def validate(cls, **kwargs: Any) -> None:
        enum_class = kwargs.get("enum_class")
        if enum_class is None or not isinstance(enum_class, EnumMeta):
            raise ModelDefinitionError("Enum Field choices must be EnumType")

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        enum_cls = kwargs.get("enum_class")
        return sqlalchemy.Enum(enum_cls)

ExcludableItems

Keeps a dictionary of Excludables by alias + model_name keys to allow quick lookup by nested models without need to travers deeply nested dictionaries and passing include/exclude around

Source code in ormar/models/excludable.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 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
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
class ExcludableItems:
    """
    Keeps a dictionary of Excludables by alias + model_name keys
    to allow quick lookup by nested models without need to travers
    deeply nested dictionaries and passing include/exclude around
    """

    def __init__(self) -> None:
        self.items: Dict[str, Excludable] = dict()

    @classmethod
    def from_excludable(cls, other: "ExcludableItems") -> "ExcludableItems":
        """
        Copy passed ExcludableItems to avoid inplace modifications.

        :param other: other excludable items to be copied
        :type other: ormar.models.excludable.ExcludableItems
        :return: copy of other
        :rtype: ormar.models.excludable.ExcludableItems
        """
        new_excludable = cls()
        for key, value in other.items.items():
            new_excludable.items[key] = value.get_copy()
        return new_excludable

    def include_entry_count(self) -> int:
        """
        Returns count of include items inside
        """
        count = 0
        for key in self.items.keys():
            count += len(self.items[key].include)
        return count

    def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
        """
        Return Excludable for given model and alias.

        :param model_cls: target model to check
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param alias: table alias from relation manager
        :type alias: str
        :return: Excludable for given model and alias
        :rtype: ormar.models.excludable.Excludable
        """
        key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
        excludable = self.items.get(key)
        if not excludable:
            excludable = Excludable()
            self.items[key] = excludable
        return excludable

    def build(
        self,
        items: Union[List[str], str, Tuple[str], Set[str], Dict],
        model_cls: Type["Model"],
        is_exclude: bool = False,
    ) -> None:
        """
        Receives the one of the types of items and parses them as to achieve
        a end situation with one excludable per alias/model in relation.

        Each excludable has two sets of values - one to include, one to exclude.

        :param items: values to be included or excluded
        :type items: Union[List[str], str, Tuple[str], Set[str], Dict]
        :param model_cls: source model from which relations are constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if items should be included or excluded
        :type is_exclude: bool
        """
        if isinstance(items, str):
            items = {items}

        if isinstance(items, Dict):
            self._traverse_dict(
                values=items,
                source_model=model_cls,
                model_cls=model_cls,
                is_exclude=is_exclude,
            )

        else:
            items = set(items)
            nested_items = set(x for x in items if "__" in x)
            items.difference_update(nested_items)
            self._set_excludes(
                items=items,
                model_name=model_cls.get_name(lower=True),
                is_exclude=is_exclude,
            )
            if nested_items:
                self._traverse_list(
                    values=nested_items, model_cls=model_cls, is_exclude=is_exclude
                )

    def _set_excludes(
        self, items: Set, model_name: str, is_exclude: bool, alias: str = ""
    ) -> None:
        """
        Sets set of values to be included or excluded for given key and model.

        :param items: items to include/exclude
        :type items: set
        :param model_name: name of model to construct key
        :type model_name: str
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        :param alias:
        :type alias: str
        """
        key = f"{alias + '_' if alias else ''}{model_name}"
        excludable = self.items.get(key)
        if not excludable:
            excludable = Excludable()
        excludable.set_values(value=items, is_exclude=is_exclude)
        self.items[key] = excludable

    def _traverse_dict(  # noqa: CFQ002
        self,
        values: Dict,
        source_model: Type["Model"],
        model_cls: Type["Model"],
        is_exclude: bool,
        related_items: List = None,
        alias: str = "",
    ) -> None:
        """
        Goes through dict of nested values and construct/update Excludables.

        :param values: items to include/exclude
        :type values: Dict
        :param source_model: source model from which relations are constructed
        :type source_model: ormar.models.metaclass.ModelMetaclass
        :param model_cls: model from which current relation is constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        :param related_items: list of names of related fields chain
        :type related_items: List
        :param alias: alias of relation
        :type alias: str
        """
        self_fields = set()
        related_items = related_items[:] if related_items else []
        for key, value in values.items():
            if value is ...:
                self_fields.add(key)
            elif isinstance(value, set):
                (
                    table_prefix,
                    target_model,
                    _,
                    _,
                ) = get_relationship_alias_model_and_str(
                    source_model=source_model, related_parts=related_items + [key]
                )
                self._set_excludes(
                    items=value,
                    model_name=target_model.get_name(),
                    is_exclude=is_exclude,
                    alias=table_prefix,
                )
            else:
                # dict
                related_items.append(key)
                (
                    table_prefix,
                    target_model,
                    _,
                    _,
                ) = get_relationship_alias_model_and_str(
                    source_model=source_model, related_parts=related_items
                )
                self._traverse_dict(
                    values=value,
                    source_model=source_model,
                    model_cls=target_model,
                    is_exclude=is_exclude,
                    related_items=related_items,
                    alias=table_prefix,
                )
        if self_fields:
            self._set_excludes(
                items=self_fields,
                model_name=model_cls.get_name(),
                is_exclude=is_exclude,
                alias=alias,
            )

    def _traverse_list(
        self, values: Set[str], model_cls: Type["Model"], is_exclude: bool
    ) -> None:
        """
        Goes through list of values and construct/update Excludables.

        :param values: items to include/exclude
        :type values: set
        :param model_cls: model from which current relation is constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        """
        # here we have only nested related keys
        for key in values:
            key_split = key.split("__")
            related_items, field_name = key_split[:-1], key_split[-1]
            (table_prefix, target_model, _, _) = get_relationship_alias_model_and_str(
                source_model=model_cls, related_parts=related_items
            )
            self._set_excludes(
                items={field_name},
                model_name=target_model.get_name(),
                is_exclude=is_exclude,
                alias=table_prefix,
            )

_set_excludes(items, model_name, is_exclude, alias='')

Sets set of values to be included or excluded for given key and model.

Parameters:

Name Type Description Default
items Set

items to include/exclude

required
model_name str

name of model to construct key

required
is_exclude bool

flag if values should be included or excluded

required
alias str ''
Source code in ormar/models/excludable.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def _set_excludes(
    self, items: Set, model_name: str, is_exclude: bool, alias: str = ""
) -> None:
    """
    Sets set of values to be included or excluded for given key and model.

    :param items: items to include/exclude
    :type items: set
    :param model_name: name of model to construct key
    :type model_name: str
    :param is_exclude: flag if values should be included or excluded
    :type is_exclude: bool
    :param alias:
    :type alias: str
    """
    key = f"{alias + '_' if alias else ''}{model_name}"
    excludable = self.items.get(key)
    if not excludable:
        excludable = Excludable()
    excludable.set_values(value=items, is_exclude=is_exclude)
    self.items[key] = excludable

_traverse_dict(values, source_model, model_cls, is_exclude, related_items=None, alias='')

Goes through dict of nested values and construct/update Excludables.

Parameters:

Name Type Description Default
values Dict

items to include/exclude

required
source_model Type['Model']

source model from which relations are constructed

required
model_cls Type['Model']

model from which current relation is constructed

required
is_exclude bool

flag if values should be included or excluded

required
related_items List

list of names of related fields chain

None
alias str

alias of relation

''
Source code in ormar/models/excludable.py
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
def _traverse_dict(  # noqa: CFQ002
    self,
    values: Dict,
    source_model: Type["Model"],
    model_cls: Type["Model"],
    is_exclude: bool,
    related_items: List = None,
    alias: str = "",
) -> None:
    """
    Goes through dict of nested values and construct/update Excludables.

    :param values: items to include/exclude
    :type values: Dict
    :param source_model: source model from which relations are constructed
    :type source_model: ormar.models.metaclass.ModelMetaclass
    :param model_cls: model from which current relation is constructed
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param is_exclude: flag if values should be included or excluded
    :type is_exclude: bool
    :param related_items: list of names of related fields chain
    :type related_items: List
    :param alias: alias of relation
    :type alias: str
    """
    self_fields = set()
    related_items = related_items[:] if related_items else []
    for key, value in values.items():
        if value is ...:
            self_fields.add(key)
        elif isinstance(value, set):
            (
                table_prefix,
                target_model,
                _,
                _,
            ) = get_relationship_alias_model_and_str(
                source_model=source_model, related_parts=related_items + [key]
            )
            self._set_excludes(
                items=value,
                model_name=target_model.get_name(),
                is_exclude=is_exclude,
                alias=table_prefix,
            )
        else:
            # dict
            related_items.append(key)
            (
                table_prefix,
                target_model,
                _,
                _,
            ) = get_relationship_alias_model_and_str(
                source_model=source_model, related_parts=related_items
            )
            self._traverse_dict(
                values=value,
                source_model=source_model,
                model_cls=target_model,
                is_exclude=is_exclude,
                related_items=related_items,
                alias=table_prefix,
            )
    if self_fields:
        self._set_excludes(
            items=self_fields,
            model_name=model_cls.get_name(),
            is_exclude=is_exclude,
            alias=alias,
        )

_traverse_list(values, model_cls, is_exclude)

Goes through list of values and construct/update Excludables.

Parameters:

Name Type Description Default
values Set[str]

items to include/exclude

required
model_cls Type['Model']

model from which current relation is constructed

required
is_exclude bool

flag if values should be included or excluded

required
Source code in ormar/models/excludable.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def _traverse_list(
    self, values: Set[str], model_cls: Type["Model"], is_exclude: bool
) -> None:
    """
    Goes through list of values and construct/update Excludables.

    :param values: items to include/exclude
    :type values: set
    :param model_cls: model from which current relation is constructed
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param is_exclude: flag if values should be included or excluded
    :type is_exclude: bool
    """
    # here we have only nested related keys
    for key in values:
        key_split = key.split("__")
        related_items, field_name = key_split[:-1], key_split[-1]
        (table_prefix, target_model, _, _) = get_relationship_alias_model_and_str(
            source_model=model_cls, related_parts=related_items
        )
        self._set_excludes(
            items={field_name},
            model_name=target_model.get_name(),
            is_exclude=is_exclude,
            alias=table_prefix,
        )

build(items, model_cls, is_exclude=False)

Receives the one of the types of items and parses them as to achieve a end situation with one excludable per alias/model in relation.

Each excludable has two sets of values - one to include, one to exclude.

Parameters:

Name Type Description Default
items Union[List[str], str, Tuple[str], Set[str], Dict]

values to be included or excluded

required
model_cls Type['Model']

source model from which relations are constructed

required
is_exclude bool

flag if items should be included or excluded

False
Source code in ormar/models/excludable.py
117
118
119
120
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
156
157
158
159
def build(
    self,
    items: Union[List[str], str, Tuple[str], Set[str], Dict],
    model_cls: Type["Model"],
    is_exclude: bool = False,
) -> None:
    """
    Receives the one of the types of items and parses them as to achieve
    a end situation with one excludable per alias/model in relation.

    Each excludable has two sets of values - one to include, one to exclude.

    :param items: values to be included or excluded
    :type items: Union[List[str], str, Tuple[str], Set[str], Dict]
    :param model_cls: source model from which relations are constructed
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param is_exclude: flag if items should be included or excluded
    :type is_exclude: bool
    """
    if isinstance(items, str):
        items = {items}

    if isinstance(items, Dict):
        self._traverse_dict(
            values=items,
            source_model=model_cls,
            model_cls=model_cls,
            is_exclude=is_exclude,
        )

    else:
        items = set(items)
        nested_items = set(x for x in items if "__" in x)
        items.difference_update(nested_items)
        self._set_excludes(
            items=items,
            model_name=model_cls.get_name(lower=True),
            is_exclude=is_exclude,
        )
        if nested_items:
            self._traverse_list(
                values=nested_items, model_cls=model_cls, is_exclude=is_exclude
            )

from_excludable(other) classmethod

Copy passed ExcludableItems to avoid inplace modifications.

Parameters:

Name Type Description Default
other 'ExcludableItems'

other excludable items to be copied

required

Returns:

Type Description
ormar.models.excludable.ExcludableItems

copy of other

Source code in ormar/models/excludable.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@classmethod
def from_excludable(cls, other: "ExcludableItems") -> "ExcludableItems":
    """
    Copy passed ExcludableItems to avoid inplace modifications.

    :param other: other excludable items to be copied
    :type other: ormar.models.excludable.ExcludableItems
    :return: copy of other
    :rtype: ormar.models.excludable.ExcludableItems
    """
    new_excludable = cls()
    for key, value in other.items.items():
        new_excludable.items[key] = value.get_copy()
    return new_excludable

get(model_cls, alias='')

Return Excludable for given model and alias.

Parameters:

Name Type Description Default
model_cls Type['Model']

target model to check

required
alias str

table alias from relation manager

''

Returns:

Type Description
ormar.models.excludable.Excludable

Excludable for given model and alias

Source code in ormar/models/excludable.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
    """
    Return Excludable for given model and alias.

    :param model_cls: target model to check
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param alias: table alias from relation manager
    :type alias: str
    :return: Excludable for given model and alias
    :rtype: ormar.models.excludable.Excludable
    """
    key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
    excludable = self.items.get(key)
    if not excludable:
        excludable = Excludable()
        self.items[key] = excludable
    return excludable

include_entry_count()

Returns count of include items inside

Source code in ormar/models/excludable.py
90
91
92
93
94
95
96
97
def include_entry_count(self) -> int:
    """
    Returns count of include items inside
    """
    count = 0
    for key in self.items.keys():
        count += len(self.items[key].include)
    return count

Float

Bases: ModelFieldFactory, float

Float field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
class Float(ModelFieldFactory, float):
    """
    Float field factory that construct Field classes and populated their values.
    """

    _type = float
    _sample = 0.0

    def __new__(  # type: ignore
        cls,
        *,
        minimum: float = None,
        maximum: float = None,
        multiple_of: int = None,
        **kwargs: Any
    ) -> BaseField:
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        kwargs["ge"] = kwargs["minimum"]
        kwargs["le"] = kwargs["maximum"]
        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.Float()

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
367
368
369
370
371
372
373
374
375
376
377
378
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.Float()

ForeignKeyField

Bases: BaseField

Actual class returned from ForeignKey function call and stored in model_fields.

Source code in ormar/fields/foreign_key.py
287
288
289
290
291
292
293
294
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
class ForeignKeyField(BaseField):
    """
    Actual class returned from ForeignKey function call and stored in model_fields.
    """

    def __init__(self, **kwargs: Any) -> None:
        if TYPE_CHECKING:  # pragma: no cover
            self.__type__: type
            self.to: Type["Model"]
        self.ondelete: str = kwargs.pop("ondelete", None)
        self.onupdate: str = kwargs.pop("onupdate", None)
        super().__init__(**kwargs)

    def get_source_related_name(self) -> str:
        """
        Returns name to use for source relation name.
        For FK it's the same, differs for m2m fields.
        It's either set as `related_name` or by default it's owner model. get_name + 's'
        :return: name of the related_name or default related name.
        :rtype: str
        """
        return self.get_related_name()

    def get_related_name(self) -> str:
        """
        Returns name to use for reverse relation.
        It's either set as `related_name` or by default it's owner model. get_name + 's'
        :return: name of the related_name or default related name.
        :rtype: str
        """
        return self.related_name or self.owner.get_name() + "s"

    def default_target_field_name(self) -> str:
        """
        Returns default target model name on through model.
        :return: name of the field
        :rtype: str
        """
        prefix = "from_" if self.self_reference else ""
        return self.through_reverse_relation_name or f"{prefix}{self.to.get_name()}"

    def default_source_field_name(self) -> str:
        """
        Returns default target model name on through model.
        :return: name of the field
        :rtype: str
        """
        prefix = "to_" if self.self_reference else ""
        return self.through_relation_name or f"{prefix}{self.owner.get_name()}"

    def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
        """
        Evaluates the ForwardRef to actual Field based on global and local namespaces

        :param globalns: global namespace
        :type globalns: Any
        :param localns: local namespace
        :type localns: Any
        :return: None
        :rtype: None
        """
        if self.to.__class__ == ForwardRef:
            self.to = evaluate_forwardref(
                self.to, globalns, localns or None  # type: ignore
            )
            (
                self.__type__,
                self.constraints,
                self.column_type,
            ) = populate_fk_params_based_on_to_model(
                to=self.to,
                nullable=self.nullable,
                ondelete=self.ondelete,
                onupdate=self.onupdate,
            )

    def _extract_model_from_sequence(
        self, value: List, child: "Model", to_register: bool
    ) -> List["Model"]:
        """
        Takes a list of Models and registers them on parent.
        Registration is mutual, so children have also reference to parent.

        Used in reverse FK relations.

        :param value: list of Model
        :type value: List
        :param child: child/ related Model
        :type child: Model
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: list (if needed) registered Models
        :rtype: List["Model"]
        """
        return [
            self.expand_relationship(  # type: ignore
                value=val, child=child, to_register=to_register
            )
            for val in value
        ]

    def _register_existing_model(
        self, value: "Model", child: "Model", to_register: bool
    ) -> "Model":
        """
        Takes already created instance and registers it for parent.
        Registration is mutual, so children have also reference to parent.

        Used in reverse FK relations and normal FK for single models.

        :param value: already instantiated Model
        :type value: Model
        :param child: child/ related Model
        :type child: Model
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: (if needed) registered Model
        :rtype: Model
        """
        if to_register:
            self.register_relation(model=value, child=child)
        return value

    def _construct_model_from_dict(
        self, value: dict, child: "Model", to_register: bool
    ) -> "Model":
        """
        Takes a dictionary, creates a instance and registers it for parent.
        If dictionary contains only one field and it's a pk it is a __pk_only__ model.
        Registration is mutual, so children have also reference to parent.

        Used in normal FK for dictionaries.

        :param value: dictionary of a Model
        :type value: dict
        :param child: child/ related Model
        :type child: Model
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: (if needed) registered Model
        :rtype: Model
        """
        if len(value.keys()) == 1 and list(value.keys())[0] == self.to.Meta.pkname:
            value["__pk_only__"] = True
        model = self.to(**value)
        if to_register:
            self.register_relation(model=model, child=child)
        return model

    def _construct_model_from_pk(
        self, value: Any, child: "Model", to_register: bool
    ) -> "Model":
        """
        Takes a pk value, creates a dummy instance and registers it for parent.
        Registration is mutual, so children have also reference to parent.

        Used in normal FK for dictionaries.

        :param value: value of a related pk / fk column
        :type value: Any
        :param child: child/ related Model
        :type child: Model
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: (if needed) registered Model
        :rtype: Model
        """
        if self.to.pk_type() == uuid.UUID and isinstance(value, str):  # pragma: nocover
            value = uuid.UUID(value)
        if not isinstance(value, self.to.pk_type()):
            raise RelationshipInstanceError(
                f"Relationship error - ForeignKey {self.to.__name__} "
                f"is of type {self.to.pk_type()} "
                f"while {type(value)} passed as a parameter."
            )
        model = create_dummy_instance(fk=self.to, pk=value)
        if to_register:
            self.register_relation(model=model, child=child)
        return model

    def register_relation(self, model: "Model", child: "Model") -> None:
        """
        Registers relation between parent and child in relation manager.
        Relation manager is kep on each model (different instance).

        Used in Metaclass and sometimes some relations are missing
        (i.e. cloned Models in fastapi might miss one).

        :param model: parent model (with relation definition)
        :type model: Model class
        :param child: child model
        :type child: Model class
        """
        model._orm.add(parent=model, child=child, field=self)

    def has_unresolved_forward_refs(self) -> bool:
        """
        Verifies if the filed has any ForwardRefs that require updating before the
        model can be used.

        :return: result of the check
        :rtype: bool
        """
        return self.to.__class__ == ForwardRef

    def expand_relationship(
        self,
        value: Any,
        child: Union["Model", "NewBaseModel"],
        to_register: bool = True,
    ) -> Optional[Union["Model", List["Model"]]]:
        """
        For relations the child model is first constructed (if needed),
        registered in relation and returned.
        For relation fields the value can be a pk value (Any type of field),
        dict (from Model) or actual instance/list of a "Model".

        Selects the appropriate constructor based on a passed value.

        :param value: a Model field value, returned untouched for non relation fields.
        :type value: Any
        :param child: a child Model to register
        :type child: Union["Model", "NewBaseModel"]
        :param to_register: flag if the relation should be set in RelationshipManager
        :type to_register: bool
        :return: returns a Model or a list of Models
        :rtype: Optional[Union["Model", List["Model"]]]
        """
        if value is None:
            return None if not self.virtual else []
        constructors = {
            f"{self.to.__name__}": self._register_existing_model,
            "dict": self._construct_model_from_dict,
            "list": self._extract_model_from_sequence,
        }

        model = constructors.get(  # type: ignore
            value.__class__.__name__, self._construct_model_from_pk
        )(value, child, to_register)
        return model

    def get_relation_name(self) -> str:  # pragma: no cover
        """
        Returns name of the relation, which can be a own name or through model
        names for m2m models

        :return: result of the check
        :rtype: bool
        """
        return self.name

    def get_source_model(self) -> Type["Model"]:  # pragma: no cover
        """
        Returns model from which the relation comes -> either owner or through model

        :return: source model
        :rtype: Type["Model"]
        """
        return self.owner

_construct_model_from_dict(value, child, to_register)

Takes a dictionary, creates a instance and registers it for parent. If dictionary contains only one field and it's a pk it is a pk_only model. Registration is mutual, so children have also reference to parent.

Used in normal FK for dictionaries.

Parameters:

Name Type Description Default
value dict

dictionary of a Model

required
child 'Model'

child/ related Model

required
to_register bool

flag if the relation should be set in RelationshipManager

required

Returns:

Type Description
Model

(if needed) registered Model

Source code in ormar/fields/foreign_key.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
def _construct_model_from_dict(
    self, value: dict, child: "Model", to_register: bool
) -> "Model":
    """
    Takes a dictionary, creates a instance and registers it for parent.
    If dictionary contains only one field and it's a pk it is a __pk_only__ model.
    Registration is mutual, so children have also reference to parent.

    Used in normal FK for dictionaries.

    :param value: dictionary of a Model
    :type value: dict
    :param child: child/ related Model
    :type child: Model
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: (if needed) registered Model
    :rtype: Model
    """
    if len(value.keys()) == 1 and list(value.keys())[0] == self.to.Meta.pkname:
        value["__pk_only__"] = True
    model = self.to(**value)
    if to_register:
        self.register_relation(model=model, child=child)
    return model

_construct_model_from_pk(value, child, to_register)

Takes a pk value, creates a dummy instance and registers it for parent. Registration is mutual, so children have also reference to parent.

Used in normal FK for dictionaries.

Parameters:

Name Type Description Default
value Any

value of a related pk / fk column

required
child 'Model'

child/ related Model

required
to_register bool

flag if the relation should be set in RelationshipManager

required

Returns:

Type Description
Model

(if needed) registered Model

Source code in ormar/fields/foreign_key.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
def _construct_model_from_pk(
    self, value: Any, child: "Model", to_register: bool
) -> "Model":
    """
    Takes a pk value, creates a dummy instance and registers it for parent.
    Registration is mutual, so children have also reference to parent.

    Used in normal FK for dictionaries.

    :param value: value of a related pk / fk column
    :type value: Any
    :param child: child/ related Model
    :type child: Model
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: (if needed) registered Model
    :rtype: Model
    """
    if self.to.pk_type() == uuid.UUID and isinstance(value, str):  # pragma: nocover
        value = uuid.UUID(value)
    if not isinstance(value, self.to.pk_type()):
        raise RelationshipInstanceError(
            f"Relationship error - ForeignKey {self.to.__name__} "
            f"is of type {self.to.pk_type()} "
            f"while {type(value)} passed as a parameter."
        )
    model = create_dummy_instance(fk=self.to, pk=value)
    if to_register:
        self.register_relation(model=model, child=child)
    return model

_extract_model_from_sequence(value, child, to_register)

Takes a list of Models and registers them on parent. Registration is mutual, so children have also reference to parent.

Used in reverse FK relations.

Parameters:

Name Type Description Default
value List

list of Model

required
child 'Model'

child/ related Model

required
to_register bool

flag if the relation should be set in RelationshipManager

required

Returns:

Type Description
List["Model"]

list (if needed) registered Models

Source code in ormar/fields/foreign_key.py
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
def _extract_model_from_sequence(
    self, value: List, child: "Model", to_register: bool
) -> List["Model"]:
    """
    Takes a list of Models and registers them on parent.
    Registration is mutual, so children have also reference to parent.

    Used in reverse FK relations.

    :param value: list of Model
    :type value: List
    :param child: child/ related Model
    :type child: Model
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: list (if needed) registered Models
    :rtype: List["Model"]
    """
    return [
        self.expand_relationship(  # type: ignore
            value=val, child=child, to_register=to_register
        )
        for val in value
    ]

_register_existing_model(value, child, to_register)

Takes already created instance and registers it for parent. Registration is mutual, so children have also reference to parent.

Used in reverse FK relations and normal FK for single models.

Parameters:

Name Type Description Default
value 'Model'

already instantiated Model

required
child 'Model'

child/ related Model

required
to_register bool

flag if the relation should be set in RelationshipManager

required

Returns:

Type Description
Model

(if needed) registered Model

Source code in ormar/fields/foreign_key.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
def _register_existing_model(
    self, value: "Model", child: "Model", to_register: bool
) -> "Model":
    """
    Takes already created instance and registers it for parent.
    Registration is mutual, so children have also reference to parent.

    Used in reverse FK relations and normal FK for single models.

    :param value: already instantiated Model
    :type value: Model
    :param child: child/ related Model
    :type child: Model
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: (if needed) registered Model
    :rtype: Model
    """
    if to_register:
        self.register_relation(model=value, child=child)
    return value

default_source_field_name()

Returns default target model name on through model.

Returns:

Type Description
str

name of the field

Source code in ormar/fields/foreign_key.py
328
329
330
331
332
333
334
335
def default_source_field_name(self) -> str:
    """
    Returns default target model name on through model.
    :return: name of the field
    :rtype: str
    """
    prefix = "to_" if self.self_reference else ""
    return self.through_relation_name or f"{prefix}{self.owner.get_name()}"

default_target_field_name()

Returns default target model name on through model.

Returns:

Type Description
str

name of the field

Source code in ormar/fields/foreign_key.py
319
320
321
322
323
324
325
326
def default_target_field_name(self) -> str:
    """
    Returns default target model name on through model.
    :return: name of the field
    :rtype: str
    """
    prefix = "from_" if self.self_reference else ""
    return self.through_reverse_relation_name or f"{prefix}{self.to.get_name()}"

evaluate_forward_ref(globalns, localns)

Evaluates the ForwardRef to actual Field based on global and local namespaces

Parameters:

Name Type Description Default
globalns Any

global namespace

required
localns Any

local namespace

required

Returns:

Type Description
None

None

Source code in ormar/fields/foreign_key.py
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
    """
    Evaluates the ForwardRef to actual Field based on global and local namespaces

    :param globalns: global namespace
    :type globalns: Any
    :param localns: local namespace
    :type localns: Any
    :return: None
    :rtype: None
    """
    if self.to.__class__ == ForwardRef:
        self.to = evaluate_forwardref(
            self.to, globalns, localns or None  # type: ignore
        )
        (
            self.__type__,
            self.constraints,
            self.column_type,
        ) = populate_fk_params_based_on_to_model(
            to=self.to,
            nullable=self.nullable,
            ondelete=self.ondelete,
            onupdate=self.onupdate,
        )

expand_relationship(value, child, to_register=True)

For relations the child model is first constructed (if needed), registered in relation and returned. For relation fields the value can be a pk value (Any type of field), dict (from Model) or actual instance/list of a "Model".

Selects the appropriate constructor based on a passed value.

Parameters:

Name Type Description Default
value Any

a Model field value, returned untouched for non relation fields.

required
child Union['Model', 'NewBaseModel']

a child Model to register

required
to_register bool

flag if the relation should be set in RelationshipManager

True

Returns:

Type Description
Optional[Union["Model", List["Model"]]]

returns a Model or a list of Models

Source code in ormar/fields/foreign_key.py
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
def expand_relationship(
    self,
    value: Any,
    child: Union["Model", "NewBaseModel"],
    to_register: bool = True,
) -> Optional[Union["Model", List["Model"]]]:
    """
    For relations the child model is first constructed (if needed),
    registered in relation and returned.
    For relation fields the value can be a pk value (Any type of field),
    dict (from Model) or actual instance/list of a "Model".

    Selects the appropriate constructor based on a passed value.

    :param value: a Model field value, returned untouched for non relation fields.
    :type value: Any
    :param child: a child Model to register
    :type child: Union["Model", "NewBaseModel"]
    :param to_register: flag if the relation should be set in RelationshipManager
    :type to_register: bool
    :return: returns a Model or a list of Models
    :rtype: Optional[Union["Model", List["Model"]]]
    """
    if value is None:
        return None if not self.virtual else []
    constructors = {
        f"{self.to.__name__}": self._register_existing_model,
        "dict": self._construct_model_from_dict,
        "list": self._extract_model_from_sequence,
    }

    model = constructors.get(  # type: ignore
        value.__class__.__name__, self._construct_model_from_pk
    )(value, child, to_register)
    return model

Returns name to use for reverse relation. It's either set as related_name or by default it's owner model. get_name + 's'

Returns:

Type Description
str

name of the related_name or default related name.

Source code in ormar/fields/foreign_key.py
310
311
312
313
314
315
316
317
def get_related_name(self) -> str:
    """
    Returns name to use for reverse relation.
    It's either set as `related_name` or by default it's owner model. get_name + 's'
    :return: name of the related_name or default related name.
    :rtype: str
    """
    return self.related_name or self.owner.get_name() + "s"

get_relation_name()

Returns name of the relation, which can be a own name or through model names for m2m models

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/foreign_key.py
528
529
530
531
532
533
534
535
536
def get_relation_name(self) -> str:  # pragma: no cover
    """
    Returns name of the relation, which can be a own name or through model
    names for m2m models

    :return: result of the check
    :rtype: bool
    """
    return self.name

get_source_model()

Returns model from which the relation comes -> either owner or through model

Returns:

Type Description
Type["Model"]

source model

Source code in ormar/fields/foreign_key.py
538
539
540
541
542
543
544
545
def get_source_model(self) -> Type["Model"]:  # pragma: no cover
    """
    Returns model from which the relation comes -> either owner or through model

    :return: source model
    :rtype: Type["Model"]
    """
    return self.owner

Returns name to use for source relation name. For FK it's the same, differs for m2m fields. It's either set as related_name or by default it's owner model. get_name + 's'

Returns:

Type Description
str

name of the related_name or default related name.

Source code in ormar/fields/foreign_key.py
300
301
302
303
304
305
306
307
308
def get_source_related_name(self) -> str:
    """
    Returns name to use for source relation name.
    For FK it's the same, differs for m2m fields.
    It's either set as `related_name` or by default it's owner model. get_name + 's'
    :return: name of the related_name or default related name.
    :rtype: str
    """
    return self.get_related_name()

has_unresolved_forward_refs()

Verifies if the filed has any ForwardRefs that require updating before the model can be used.

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/foreign_key.py
482
483
484
485
486
487
488
489
490
def has_unresolved_forward_refs(self) -> bool:
    """
    Verifies if the filed has any ForwardRefs that require updating before the
    model can be used.

    :return: result of the check
    :rtype: bool
    """
    return self.to.__class__ == ForwardRef

register_relation(model, child)

Registers relation between parent and child in relation manager. Relation manager is kep on each model (different instance).

Used in Metaclass and sometimes some relations are missing (i.e. cloned Models in fastapi might miss one).

Parameters:

Name Type Description Default
model 'Model'

parent model (with relation definition)

required
child 'Model'

child model

required
Source code in ormar/fields/foreign_key.py
467
468
469
470
471
472
473
474
475
476
477
478
479
480
def register_relation(self, model: "Model", child: "Model") -> None:
    """
    Registers relation between parent and child in relation manager.
    Relation manager is kep on each model (different instance).

    Used in Metaclass and sometimes some relations are missing
    (i.e. cloned Models in fastapi might miss one).

    :param model: parent model (with relation definition)
    :type model: Model class
    :param child: child model
    :type child: Model class
    """
    model._orm.add(parent=model, child=child, field=self)

Integer

Bases: ModelFieldFactory, int

Integer field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
class Integer(ModelFieldFactory, int):
    """
    Integer field factory that construct Field classes and populated their values.
    """

    _type = int
    _sample = 0

    def __new__(  # type: ignore
        cls,
        *,
        minimum: int = None,
        maximum: int = None,
        multiple_of: int = None,
        **kwargs: Any
    ) -> BaseField:
        autoincrement = kwargs.pop("autoincrement", None)
        autoincrement = (
            autoincrement
            if autoincrement is not None
            else kwargs.get("primary_key", False)
        )
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        kwargs["ge"] = kwargs["minimum"]
        kwargs["le"] = kwargs["maximum"]
        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.Integer()

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
292
293
294
295
296
297
298
299
300
301
302
303
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.Integer()

JSON

Bases: ModelFieldFactory, pydantic.Json

JSON field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
class JSON(ModelFieldFactory, pydantic.Json):
    """
    JSON field factory that construct Field classes and populated their values.
    """

    _type = pydantic.Json
    _sample = '{"json": "json"}'

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.JSON(none_as_null=kwargs.get("sql_nullable", False))

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
510
511
512
513
514
515
516
517
518
519
520
521
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.JSON(none_as_null=kwargs.get("sql_nullable", False))

LargeBinary

Bases: ModelFieldFactory, bytes

LargeBinary field factory that construct Field classes and populated their values.

Source code in ormar/fields/model_fields.py
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
class LargeBinary(ModelFieldFactory, bytes):
    """
    LargeBinary field factory that construct Field classes
    and populated their values.
    """

    _type = bytes
    _sample = "bytes"

    def __new__(  # type: ignore # noqa CFQ002
        cls,
        *,
        max_length: int,
        represent_as_base64_str: bool = False,
        **kwargs: Any
    ) -> BaseField:  # type: ignore
        kwargs = {
            **kwargs,
            **{
                k: v
                for k, v in locals().items()
                if k not in ["cls", "__class__", "kwargs"]
            },
        }
        return super().__new__(cls, **kwargs)

    @classmethod
    def get_column_type(cls, **kwargs: Any) -> Any:
        """
        Return proper type of db column for given field type.
        Accepts required and optional parameters that each column type accepts.

        :param kwargs: key, value pairs of sqlalchemy options
        :type kwargs: Any
        :return: initialized column with proper options
        :rtype: sqlalchemy Column
        """
        return sqlalchemy.LargeBinary(length=kwargs.get("max_length"))

    @classmethod
    def validate(cls, **kwargs: Any) -> None:
        """
        Used to validate if all required parameters on a given field type are set.
        :param kwargs: all params passed during construction
        :type kwargs: Any
        """
        max_length = kwargs.get("max_length", None)
        if max_length <= 0:
            raise ModelDefinitionError(
                "Parameter max_length is required for field LargeBinary"
            )

get_column_type(**kwargs) classmethod

Return proper type of db column for given field type. Accepts required and optional parameters that each column type accepts.

Parameters:

Name Type Description Default
kwargs Any

key, value pairs of sqlalchemy options

required

Returns:

Type Description
sqlalchemy Column

initialized column with proper options

Source code in ormar/fields/model_fields.py
577
578
579
580
581
582
583
584
585
586
587
588
@classmethod
def get_column_type(cls, **kwargs: Any) -> Any:
    """
    Return proper type of db column for given field type.
    Accepts required and optional parameters that each column type accepts.

    :param kwargs: key, value pairs of sqlalchemy options
    :type kwargs: Any
    :return: initialized column with proper options
    :rtype: sqlalchemy Column
    """
    return sqlalchemy.LargeBinary(length=kwargs.get("max_length"))

validate(**kwargs) classmethod

Used to validate if all required parameters on a given field type are set.

Parameters:

Name Type Description Default
kwargs Any

all params passed during construction

required
Source code in ormar/fields/model_fields.py
590
591
592
593
594
595
596
597
598
599
600
601
@classmethod
def validate(cls, **kwargs: Any) -> None:
    """
    Used to validate if all required parameters on a given field type are set.
    :param kwargs: all params passed during construction
    :type kwargs: Any
    """
    max_length = kwargs.get("max_length", None)
    if max_length <= 0:
        raise ModelDefinitionError(
            "Parameter max_length is required for field LargeBinary"
        )

ManyToManyField

Bases: ForeignKeyField, ormar.QuerySetProtocol, ormar.RelationProtocol

Actual class returned from ManyToMany function call and stored in model_fields.

Source code in ormar/fields/many_to_many.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
class ManyToManyField(ForeignKeyField, ormar.QuerySetProtocol, ormar.RelationProtocol):
    """
    Actual class returned from ManyToMany function call and stored in model_fields.
    """

    def __init__(self, **kwargs: Any) -> None:
        if TYPE_CHECKING:  # pragma: no cover
            self.__type__: type
            self.to: Type["Model"]
            self.through: Type["Model"]
        super().__init__(**kwargs)

    def get_source_related_name(self) -> str:
        """
        Returns name to use for source relation name.
        For FK it's the same, differs for m2m fields.
        It's either set as `related_name` or by default it's field name.
        :return: name of the related_name or default related name.
        :rtype: str
        """
        return (
            self.through.Meta.model_fields[
                self.default_source_field_name()
            ].related_name
            or self.name
        )

    def has_unresolved_forward_refs(self) -> bool:
        """
        Verifies if the filed has any ForwardRefs that require updating before the
        model can be used.

        :return: result of the check
        :rtype: bool
        """
        return self.to.__class__ == ForwardRef or self.through.__class__ == ForwardRef

    def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
        """
        Evaluates the ForwardRef to actual Field based on global and local namespaces

        :param globalns: global namespace
        :type globalns: Any
        :param localns: local namespace
        :type localns: Any
        :return: None
        :rtype: None
        """
        if self.to.__class__ == ForwardRef:
            self.to = evaluate_forwardref(
                self.to, globalns, localns or None  # type: ignore
            )

            (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model(
                to=self.to, nullable=self.nullable
            )

        if self.through.__class__ == ForwardRef:
            self.through = evaluate_forwardref(
                self.through, globalns, localns or None  # type: ignore
            )
            forbid_through_relations(self.through)

    def get_relation_name(self) -> str:
        """
        Returns name of the relation, which can be a own name or through model
        names for m2m models

        :return: result of the check
        :rtype: bool
        """
        if self.self_reference and self.name == self.self_reference_primary:
            return self.default_source_field_name()
        return self.default_target_field_name()

    def get_source_model(self) -> Type["Model"]:
        """
        Returns model from which the relation comes -> either owner or through model

        :return: source model
        :rtype: Type["Model"]
        """
        return self.through

    def create_default_through_model(self) -> None:
        """
        Creates default empty through model if no additional fields are required.
        """
        owner_name = self.owner.get_name(lower=False)
        to_name = self.to.get_name(lower=False)
        class_name = f"{owner_name}{to_name}"
        table_name = f"{owner_name.lower()}s_{to_name.lower()}s"
        new_meta_namespace = {
            "tablename": table_name,
            "database": self.owner.Meta.database,
            "metadata": self.owner.Meta.metadata,
        }
        new_meta = type("Meta", (), new_meta_namespace)
        through_model = type(
            class_name,
            (ormar.Model,),
            {"Meta": new_meta, "id": ormar.Integer(name="id", primary_key=True)},
        )
        self.through = cast(Type["Model"], through_model)

create_default_through_model()

Creates default empty through model if no additional fields are required.

Source code in ormar/fields/many_to_many.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def create_default_through_model(self) -> None:
    """
    Creates default empty through model if no additional fields are required.
    """
    owner_name = self.owner.get_name(lower=False)
    to_name = self.to.get_name(lower=False)
    class_name = f"{owner_name}{to_name}"
    table_name = f"{owner_name.lower()}s_{to_name.lower()}s"
    new_meta_namespace = {
        "tablename": table_name,
        "database": self.owner.Meta.database,
        "metadata": self.owner.Meta.metadata,
    }
    new_meta = type("Meta", (), new_meta_namespace)
    through_model = type(
        class_name,
        (ormar.Model,),
        {"Meta": new_meta, "id": ormar.Integer(name="id", primary_key=True)},
    )
    self.through = cast(Type["Model"], through_model)

evaluate_forward_ref(globalns, localns)

Evaluates the ForwardRef to actual Field based on global and local namespaces

Parameters:

Name Type Description Default
globalns Any

global namespace

required
localns Any

local namespace

required

Returns:

Type Description
None

None

Source code in ormar/fields/many_to_many.py
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
def evaluate_forward_ref(self, globalns: Any, localns: Any) -> None:
    """
    Evaluates the ForwardRef to actual Field based on global and local namespaces

    :param globalns: global namespace
    :type globalns: Any
    :param localns: local namespace
    :type localns: Any
    :return: None
    :rtype: None
    """
    if self.to.__class__ == ForwardRef:
        self.to = evaluate_forwardref(
            self.to, globalns, localns or None  # type: ignore
        )

        (self.__type__, self.column_type) = populate_m2m_params_based_on_to_model(
            to=self.to, nullable=self.nullable
        )

    if self.through.__class__ == ForwardRef:
        self.through = evaluate_forwardref(
            self.through, globalns, localns or None  # type: ignore
        )
        forbid_through_relations(self.through)

get_relation_name()

Returns name of the relation, which can be a own name or through model names for m2m models

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/many_to_many.py
239
240
241
242
243
244
245
246
247
248
249
def get_relation_name(self) -> str:
    """
    Returns name of the relation, which can be a own name or through model
    names for m2m models

    :return: result of the check
    :rtype: bool
    """
    if self.self_reference and self.name == self.self_reference_primary:
        return self.default_source_field_name()
    return self.default_target_field_name()

get_source_model()

Returns model from which the relation comes -> either owner or through model

Returns:

Type Description
Type["Model"]

source model

Source code in ormar/fields/many_to_many.py
251
252
253
254
255
256
257
258
def get_source_model(self) -> Type["Model"]:
    """
    Returns model from which the relation comes -> either owner or through model

    :return: source model
    :rtype: Type["Model"]
    """
    return self.through

Returns name to use for source relation name. For FK it's the same, differs for m2m fields. It's either set as related_name or by default it's field name.

Returns:

Type Description
str

name of the related_name or default related name.

Source code in ormar/fields/many_to_many.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
def get_source_related_name(self) -> str:
    """
    Returns name to use for source relation name.
    For FK it's the same, differs for m2m fields.
    It's either set as `related_name` or by default it's field name.
    :return: name of the related_name or default related name.
    :rtype: str
    """
    return (
        self.through.Meta.model_fields[
            self.default_source_field_name()
        ].related_name
        or self.name
    )

has_unresolved_forward_refs()

Verifies if the filed has any ForwardRefs that require updating before the model can be used.

Returns:

Type Description
bool

result of the check

Source code in ormar/fields/many_to_many.py
203
204
205
206
207
208
209
210
211
def has_unresolved_forward_refs(self) -> bool:
    """
    Verifies if the filed has any ForwardRefs that require updating before the
    model can be used.

    :return: result of the check
    :rtype: bool
    """
    return self.to.__class__ == ForwardRef or self.through.__class__ == ForwardRef

Model

Bases: ModelRow

Source code in ormar/models/model.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 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
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
class Model(ModelRow):
    __abstract__ = False
    if TYPE_CHECKING:  # pragma nocover
        Meta: ModelMeta

    def __repr__(self) -> str:  # pragma nocover
        _repr = {
            k: getattr(self, k)
            for k, v in self.Meta.model_fields.items()
            if not v.skip_field
        }
        return f"{self.__class__.__name__}({str(_repr)})"

    async def upsert(self: T, **kwargs: Any) -> T:
        """
        Performs either a save or an update depending on the presence of the pk.
        If the pk field is filled it's an update, otherwise the save is performed.
        For save kwargs are ignored, used only in update if provided.

        :param kwargs: list of fields to update
        :type kwargs: Any
        :return: saved Model
        :rtype: Model
        """
        if not self.pk:
            return await self.save()
        return await self.update(**kwargs)

    async def save(self: T) -> T:
        """
        Performs a save of given Model instance.
        If primary key is already saved, db backend will throw integrity error.

        Related models are saved by pk number, reverse relation and many to many fields
        are not saved - use corresponding relations methods.

        If there are fields with server_default set and those fields
        are not already filled save will trigger also a second query
        to refreshed the fields populated server side.

        Does not recognize if model was previously saved.
        If you want to perform update or insert depending on the pk
        fields presence use upsert.

        Sends pre_save and post_save signals.

        Sets model save status to True.

        :return: saved Model
        :rtype: Model
        """
        await self.signals.pre_save.send(sender=self.__class__, instance=self)
        self_fields = self._extract_model_db_fields()

        if not self.pk and self.Meta.model_fields[self.Meta.pkname].autoincrement:
            self_fields.pop(self.Meta.pkname, None)
        self_fields = self.populate_default_values(self_fields)
        self.update_from_dict(
            {
                k: v
                for k, v in self_fields.items()
                if k not in self.extract_related_names()
            }
        )

        self_fields = self.translate_columns_to_aliases(self_fields)
        expr = self.Meta.table.insert()
        expr = expr.values(**self_fields)

        pk = await self.Meta.database.execute(expr)
        if pk and isinstance(pk, self.pk_type()):
            setattr(self, self.Meta.pkname, pk)

        self.set_save_status(True)
        # refresh server side defaults
        if any(
            field.server_default is not None
            for name, field in self.Meta.model_fields.items()
            if name not in self_fields
        ):
            await self.load()

        await self.signals.post_save.send(sender=self.__class__, instance=self)
        return self

    async def save_related(  # noqa: CCR001, CFQ002
        self,
        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
        if the instances are not already saved.
        By default saves only the directly related ones.

        If follow=True is set it saves also related models of related models.

        To not get stuck in an infinite loop as related models also keep a relation
        to parent model visited models set is kept.

        That way already visited models that are nested are saved, but the save do not
        follow them inside. So Model A -> Model B -> Model A -> Model C will save second
        Model A but will never follow into Model C.
        Nested relations of those kind need to be persisted manually.

        :param relation_field: field with relation leading to this model
        :type relation_field: Optional[ForeignKeyField]
        :param previous_model: previous model from which method came
        :type previous_model: Model
        :param exclude: items to exclude during saving of relations
        :type exclude: Union[Set, Dict]
        :param relation_map: map of relations to follow
        :type relation_map: Dict
        :param save_all: flag if all models should be saved or only not saved ones
        :type save_all: bool
        :param follow: flag to trigger deep save -
        by default only directly related models are saved
        with follow=True also related models of related models are saved
        :type follow: bool
        :param update_count: internal parameter for recursive calls -
        number of updated instances
        :type update_count: int
        :return: number of updated/saved models
        :rtype: int
        """
        relation_map = (
            relation_map
            if relation_map is not None
            else translate_list_to_dict(self._iterate_related_models())
        )
        if exclude and isinstance(exclude, Set):
            exclude = translate_list_to_dict(exclude)
        relation_map = subtract_dict(relation_map, exclude or {})

        if relation_map:
            fields_to_visit = {
                field
                for field in self.extract_related_fields()
                if field.name in relation_map
            }
            pre_save = {
                field
                for field in fields_to_visit
                if not field.virtual and not field.is_multi
            }

            update_count = await self._update_relation_list(
                fields_list=pre_save,
                follow=follow,
                save_all=save_all,
                relation_map=relation_map,
                update_count=update_count,
            )

            update_count = await self._upsert_model(
                instance=self,
                save_all=save_all,
                previous_model=previous_model,
                relation_field=relation_field,
                update_count=update_count,
            )

            post_save = fields_to_visit - pre_save

            update_count = await self._update_relation_list(
                fields_list=post_save,
                follow=follow,
                save_all=save_all,
                relation_map=relation_map,
                update_count=update_count,
            )

        else:
            update_count = await self._upsert_model(
                instance=self,
                save_all=save_all,
                previous_model=previous_model,
                relation_field=relation_field,
                update_count=update_count,
            )

        return update_count

    async def update(self: T, _columns: List[str] = None, **kwargs: Any) -> T:
        """
        Performs update of Model instance in the database.
        Fields can be updated before or you can pass them as kwargs.

        Sends pre_update and post_update signals.

        Sets model save status to True.

        :param _columns: list of columns to update, if None all are updated
        :type _columns: List
        :raises ModelPersistenceError: If the pk column is not set

        :param kwargs: list of fields to update as field=value pairs
        :type kwargs: Any
        :return: updated Model
        :rtype: Model
        """
        if kwargs:
            self.update_from_dict(kwargs)

        if not self.pk:
            raise ModelPersistenceError(
                "You cannot update not saved model! Use save or upsert method."
            )

        await self.signals.pre_update.send(
            sender=self.__class__, instance=self, passed_args=kwargs
        )
        self_fields = self._extract_model_db_fields()
        self_fields.pop(self.get_column_name_from_alias(self.Meta.pkname))
        if _columns:
            self_fields = {k: v for k, v in self_fields.items() if k in _columns}
        self_fields = self.translate_columns_to_aliases(self_fields)
        expr = self.Meta.table.update().values(**self_fields)
        expr = expr.where(self.pk_column == getattr(self, self.Meta.pkname))

        await self.Meta.database.execute(expr)
        self.set_save_status(True)
        await self.signals.post_update.send(sender=self.__class__, instance=self)
        return self

    async def delete(self) -> int:
        """
        Removes the Model instance from the database.

        Sends pre_delete and post_delete signals.

        Sets model save status to False.

        Note it does not delete the Model itself (python object).
        So you can delete and later save (since pk is deleted no conflict will arise)
        or update and the Model will be saved in database again.

        :return: number of deleted rows (for some backends)
        :rtype: int
        """
        await self.signals.pre_delete.send(sender=self.__class__, instance=self)
        expr = self.Meta.table.delete()
        expr = expr.where(self.pk_column == (getattr(self, self.Meta.pkname)))
        result = await self.Meta.database.execute(expr)
        self.set_save_status(False)
        await self.signals.post_delete.send(sender=self.__class__, instance=self)
        return result

    async def load(self: T) -> T:
        """
        Allow to refresh existing Models fields from database.
        Be careful as the related models can be overwritten by pk_only models in load.
        Does NOT refresh the related models fields if they were loaded before.

        :raises NoMatch: If given pk is not found in database.

        :return: reloaded Model
        :rtype: Model
        """
        expr = self.Meta.table.select().where(self.pk_column == self.pk)
        row = await self.Meta.database.fetch_one(expr)
        if not row:  # pragma nocover
            raise NoMatch("Instance was deleted from database and cannot be refreshed")
        kwargs = dict(row)
        kwargs = self.translate_aliases_to_columns(kwargs)
        self.update_from_dict(kwargs)
        self.set_save_status(True)
        return self

    async def load_all(
        self: T,
        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.
        Performs refresh of the related models fields.

        By default loads only self and the directly related ones.

        If follow=True is set it loads also related models of related models.

        To not get stuck in an infinite loop as related models also keep a relation
        to parent model visited models set is kept.

        That way already visited models that are nested are loaded, but the load do not
        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.

        :param order_by: columns by which models should be sorted
        :type order_by: Union[List, str]
        :raises NoMatch: If given pk is not found in database.

        :param exclude: related models to exclude
        :type exclude: Union[List, str, Set, Dict]
        :param follow: flag to trigger deep save -
        by default only directly related models are saved
        with follow=True also related models of related models are saved
        :type follow: bool
        :return: reloaded Model
        :rtype: Model
        """
        relations = list(self.extract_related_names())
        if follow:
            relations = self._iterate_related_models()
        queryset = self.__class__.objects
        if exclude:
            queryset = queryset.exclude_fields(exclude)
        if order_by:
            queryset = queryset.order_by(order_by)
        instance = await queryset.select_related(relations).get(pk=self.pk)
        self._orm.clear()
        self.update_from_dict(instance.dict())
        return self

delete() async

Removes the Model instance from the database.

Sends pre_delete and post_delete signals.

Sets model save status to False.

Note it does not delete the Model itself (python object). So you can delete and later save (since pk is deleted no conflict will arise) or update and the Model will be saved in database again.

Returns:

Type Description
int

number of deleted rows (for some backends)

Source code in ormar/models/model.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
async def delete(self) -> int:
    """
    Removes the Model instance from the database.

    Sends pre_delete and post_delete signals.

    Sets model save status to False.

    Note it does not delete the Model itself (python object).
    So you can delete and later save (since pk is deleted no conflict will arise)
    or update and the Model will be saved in database again.

    :return: number of deleted rows (for some backends)
    :rtype: int
    """
    await self.signals.pre_delete.send(sender=self.__class__, instance=self)
    expr = self.Meta.table.delete()
    expr = expr.where(self.pk_column == (getattr(self, self.Meta.pkname)))
    result = await self.Meta.database.execute(expr)
    self.set_save_status(False)
    await self.signals.post_delete.send(sender=self.__class__, instance=self)
    return result

load() async

Allow to refresh existing Models fields from database. Be careful as the related models can be overwritten by pk_only models in load. Does NOT refresh the related models fields if they were loaded before.

Returns:

Type Description
Model

reloaded Model

Raises:

Type Description
NoMatch

If given pk is not found in database.

Source code in ormar/models/model.py
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
async def load(self: T) -> T:
    """
    Allow to refresh existing Models fields from database.
    Be careful as the related models can be overwritten by pk_only models in load.
    Does NOT refresh the related models fields if they were loaded before.

    :raises NoMatch: If given pk is not found in database.

    :return: reloaded Model
    :rtype: Model
    """
    expr = self.Meta.table.select().where(self.pk_column == self.pk)
    row = await self.Meta.database.fetch_one(expr)
    if not row:  # pragma nocover
        raise NoMatch("Instance was deleted from database and cannot be refreshed")
    kwargs = dict(row)
    kwargs = self.translate_aliases_to_columns(kwargs)
    self.update_from_dict(kwargs)
    self.set_save_status(True)
    return self

load_all(follow=False, exclude=None, order_by=None) async

Allow to refresh existing Models fields from database. Performs refresh of the related models fields.

By default loads only self and the directly related ones.

If follow=True is set it loads also related models of related models.

To not get stuck in an infinite loop as related models also keep a relation to parent model visited models set is kept.

That way already visited models that are nested are loaded, but the load do not 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.

Parameters:

Name Type Description Default
order_by Union[List, str]

columns by which models should be sorted

None
exclude Union[List, str, Set, Dict]

related models to exclude

None
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

False

Returns:

Type Description
Model

reloaded Model

Raises:

Type Description
NoMatch

If given pk is not found in database.

Source code in ormar/models/model.py
290
291
292
293
294
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
async def load_all(
    self: T,
    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.
    Performs refresh of the related models fields.

    By default loads only self and the directly related ones.

    If follow=True is set it loads also related models of related models.

    To not get stuck in an infinite loop as related models also keep a relation
    to parent model visited models set is kept.

    That way already visited models that are nested are loaded, but the load do not
    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.

    :param order_by: columns by which models should be sorted
    :type order_by: Union[List, str]
    :raises NoMatch: If given pk is not found in database.

    :param exclude: related models to exclude
    :type exclude: Union[List, str, Set, Dict]
    :param follow: flag to trigger deep save -
    by default only directly related models are saved
    with follow=True also related models of related models are saved
    :type follow: bool
    :return: reloaded Model
    :rtype: Model
    """
    relations = list(self.extract_related_names())
    if follow:
        relations = self._iterate_related_models()
    queryset = self.__class__.objects
    if exclude:
        queryset = queryset.exclude_fields(exclude)
    if order_by:
        queryset = queryset.order_by(order_by)
    instance = await queryset.select_related(relations).get(pk=self.pk)
    self._orm.clear()
    self.update_from_dict(instance.dict())
    return self

save() async

Performs a save of given Model instance. If primary key is already saved, db backend will throw integrity error.

Related models are saved by pk number, reverse relation and many to many fields are not saved - use corresponding relations methods.

If there are fields with server_default set and those fields are not already filled save will trigger also a second query to refreshed the fields populated server side.

Does not recognize if model was previously saved. If you want to perform update or insert depending on the pk fields presence use upsert.

Sends pre_save and post_save signals.

Sets model save status to True.

Returns:

Type Description
Model

saved Model

Source code in ormar/models/model.py
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
async def save(self: T) -> T:
    """
    Performs a save of given Model instance.
    If primary key is already saved, db backend will throw integrity error.

    Related models are saved by pk number, reverse relation and many to many fields
    are not saved - use corresponding relations methods.

    If there are fields with server_default set and those fields
    are not already filled save will trigger also a second query
    to refreshed the fields populated server side.

    Does not recognize if model was previously saved.
    If you want to perform update or insert depending on the pk
    fields presence use upsert.

    Sends pre_save and post_save signals.

    Sets model save status to True.

    :return: saved Model
    :rtype: Model
    """
    await self.signals.pre_save.send(sender=self.__class__, instance=self)
    self_fields = self._extract_model_db_fields()

    if not self.pk and self.Meta.model_fields[self.Meta.pkname].autoincrement:
        self_fields.pop(self.Meta.pkname, None)
    self_fields = self.populate_default_values(self_fields)
    self.update_from_dict(
        {
            k: v
            for k, v in self_fields.items()
            if k not in self.extract_related_names()
        }
    )

    self_fields = self.translate_columns_to_aliases(self_fields)
    expr = self.Meta.table.insert()
    expr = expr.values(**self_fields)

    pk = await self.Meta.database.execute(expr)
    if pk and isinstance(pk, self.pk_type()):
        setattr(self, self.Meta.pkname, pk)

    self.set_save_status(True)
    # refresh server side defaults
    if any(
        field.server_default is not None
        for name, field in self.Meta.model_fields.items()
        if name not in self_fields
    ):
        await self.load()

    await self.signals.post_save.send(sender=self.__class__, instance=self)
    return self

Triggers a upsert method on all related models if the instances are not already saved. By default saves only the directly related ones.

If follow=True is set it saves also related models of related models.

To not get stuck in an infinite loop as related models also keep a relation to parent model visited models set is kept.

That way already visited models that are nested are saved, but the save do not follow them inside. So Model A -> Model B -> Model A -> Model C will save second Model A but will never follow into Model C. Nested relations of those kind need to be persisted manually.

Parameters:

Name Type Description Default
relation_field Optional['ForeignKeyField']

field with relation leading to this model

None
previous_model 'Model'

previous model from which method came

None
exclude Union[Set, Dict]

items to exclude during saving of relations

None
relation_map Dict

map of relations to follow

None
save_all bool

flag if all models should be saved or only not saved ones

False
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

False
update_count int

internal parameter for recursive calls - number of updated instances

0

Returns:

Type Description
int

number of updated/saved models

Source code in ormar/models/model.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
async def save_related(  # noqa: CCR001, CFQ002
    self,
    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
    if the instances are not already saved.
    By default saves only the directly related ones.

    If follow=True is set it saves also related models of related models.

    To not get stuck in an infinite loop as related models also keep a relation
    to parent model visited models set is kept.

    That way already visited models that are nested are saved, but the save do not
    follow them inside. So Model A -> Model B -> Model A -> Model C will save second
    Model A but will never follow into Model C.
    Nested relations of those kind need to be persisted manually.

    :param relation_field: field with relation leading to this model
    :type relation_field: Optional[ForeignKeyField]
    :param previous_model: previous model from which method came
    :type previous_model: Model
    :param exclude: items to exclude during saving of relations
    :type exclude: Union[Set, Dict]
    :param relation_map: map of relations to follow
    :type relation_map: Dict
    :param save_all: flag if all models should be saved or only not saved ones
    :type save_all: bool
    :param follow: flag to trigger deep save -
    by default only directly related models are saved
    with follow=True also related models of related models are saved
    :type follow: bool
    :param update_count: internal parameter for recursive calls -
    number of updated instances
    :type update_count: int
    :return: number of updated/saved models
    :rtype: int
    """
    relation_map = (
        relation_map
        if relation_map is not None
        else translate_list_to_dict(self._iterate_related_models())
    )
    if exclude and isinstance(exclude, Set):
        exclude = translate_list_to_dict(exclude)
    relation_map = subtract_dict(relation_map, exclude or {})

    if relation_map:
        fields_to_visit = {
            field
            for field in self.extract_related_fields()
            if field.name in relation_map
        }
        pre_save = {
            field
            for field in fields_to_visit
            if not field.virtual and not field.is_multi
        }

        update_count = await self._update_relation_list(
            fields_list=pre_save,
            follow=follow,
            save_all=save_all,
            relation_map=relation_map,
            update_count=update_count,
        )

        update_count = await self._upsert_model(
            instance=self,
            save_all=save_all,
            previous_model=previous_model,
            relation_field=relation_field,
            update_count=update_count,
        )

        post_save = fields_to_visit - pre_save

        update_count = await self._update_relation_list(
            fields_list=post_save,
            follow=follow,
            save_all=save_all,
            relation_map=relation_map,
            update_count=update_count,
        )

    else:
        update_count = await self._upsert_model(
            instance=self,
            save_all=save_all,
            previous_model=previous_model,
            relation_field=relation_field,
            update_count=update_count,
        )

    return update_count

update(_columns=None, **kwargs) async

Performs update of Model instance in the database. Fields can be updated before or you can pass them as kwargs.

Sends pre_update and post_update signals.

Sets model save status to True.

Parameters:

Name Type Description Default
_columns List[str]

list of columns to update, if None all are updated

None
kwargs Any

list of fields to update as field=value pairs

required

Returns:

Type Description
Model

updated Model

Raises:

Type Description
ModelPersistenceError

If the pk column is not set

Source code in ormar/models/model.py
204
205
206
207
208
209
210
211
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
async def update(self: T, _columns: List[str] = None, **kwargs: Any) -> T:
    """
    Performs update of Model instance in the database.
    Fields can be updated before or you can pass them as kwargs.

    Sends pre_update and post_update signals.

    Sets model save status to True.

    :param _columns: list of columns to update, if None all are updated
    :type _columns: List
    :raises ModelPersistenceError: If the pk column is not set

    :param kwargs: list of fields to update as field=value pairs
    :type kwargs: Any
    :return: updated Model
    :rtype: Model
    """
    if kwargs:
        self.update_from_dict(kwargs)

    if not self.pk:
        raise ModelPersistenceError(
            "You cannot update not saved model! Use save or upsert method."
        )

    await self.signals.pre_update.send(
        sender=self.__class__, instance=self, passed_args=kwargs
    )
    self_fields = self._extract_model_db_fields()
    self_fields.pop(self.get_column_name_from_alias(self.Meta.pkname))
    if _columns:
        self_fields = {k: v for k, v in self_fields.items() if k in _columns}
    self_fields = self.translate_columns_to_aliases(self_fields)
    expr = self.Meta.table.update().values(**self_fields)
    expr = expr.where(self.pk_column == getattr(self, self.Meta.pkname))

    await self.Meta.database.execute(expr)
    self.set_save_status(True)
    await self.signals.post_update.send(sender=self.__class__, instance=self)
    return self

upsert(**kwargs) async

Performs either a save or an update depending on the presence of the pk. If the pk field is filled it's an update, otherwise the save is performed. For save kwargs are ignored, used only in update if provided.

Parameters:

Name Type Description Default
kwargs Any

list of fields to update

required

Returns:

Type Description
Model

saved Model

Source code in ormar/models/model.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
async def upsert(self: T, **kwargs: Any) -> T:
    """
    Performs either a save or an update depending on the presence of the pk.
    If the pk field is filled it's an update, otherwise the save is performed.
    For save kwargs are ignored, used only in update if provided.

    :param kwargs: list of fields to update
    :type kwargs: Any
    :return: saved Model
    :rtype: Model
    """
    if not self.pk:
        return await self.save()
    return await self.update(**kwargs)

ModelDefinitionError

Bases: AsyncOrmException

Raised for errors related to the model definition itself:

  • setting @property_field on method with arguments other than func(self)
  • defining a Field without required parameters
  • defining a model with more than one primary_key
  • defining a model without primary_key
  • setting primary_key column as pydantic_only
Source code in ormar/exceptions.py
14
15
16
17
18
19
20
21
22
23
24
25
class ModelDefinitionError(AsyncOrmException):
    """
    Raised for errors related to the model definition itself:

    * setting @property_field on method with arguments other than func(self)
    * defining a Field without required parameters
    * defining a model with more than one primary_key
    * defining a model without primary_key
    * setting primary_key column as pydantic_only
    """

    pass

ModelMeta

Class used for type hinting. Users can subclass this one for convenience but it's not required. The only requirement is that ormar.Model has to have inner class with name Meta.

Source code in ormar/models/metaclass.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class ModelMeta:
    """
    Class used for type hinting.
    Users can subclass this one for convenience but it's not required.
    The only requirement is that ormar.Model has to have inner class with name Meta.
    """

    tablename: str
    table: sqlalchemy.Table
    metadata: sqlalchemy.MetaData
    database: databases.Database
    columns: List[sqlalchemy.Column]
    constraints: List[ColumnCollectionConstraint]
    pkname: str
    model_fields: Dict[str, Union[BaseField, ForeignKeyField, ManyToManyField]]
    alias_manager: AliasManager
    property_fields: Set
    signals: SignalEmitter
    abstract: bool
    requires_ref_update: bool
    orders_by: List[str]
    exclude_parent_fields: List[str]
    extra: Extra
    queryset_class: Type[QuerySet]

MultipleMatches

Bases: AsyncOrmException

Raised for database queries that should return one row (i.e. get, first etc.) but has multiple matching results in response.

Source code in ormar/exceptions.py
44
45
46
47
48
49
50
class MultipleMatches(AsyncOrmException):
    """
    Raised for database queries that should return one row (i.e. get, first etc.)
    but has multiple matching results in response.
    """

    pass

NoMatch

Bases: AsyncOrmException

Raised for database queries that has no matching result (empty result).

Source code in ormar/exceptions.py
36
37
38
39
40
41
class NoMatch(AsyncOrmException):
    """
    Raised for database queries that has no matching result (empty result).
    """

    pass

OrderAction

Bases: QueryAction

Order Actions is populated by queryset when order_by() is called.

All required params are extracted but kept raw until actual filter clause value is required -> then the action is converted into text() clause.

Extracted in order to easily change table prefixes on complex relations.

Source code in ormar/queryset/actions/order_action.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
class OrderAction(QueryAction):
    """
    Order Actions is populated by queryset when order_by() is called.

    All required params are extracted but kept raw until actual filter clause value
    is required -> then the action is converted into text() clause.

    Extracted in order to easily change table prefixes on complex relations.
    """

    def __init__(
        self, order_str: str, model_cls: Type["Model"], alias: str = None
    ) -> None:
        self.direction: str = ""
        super().__init__(query_str=order_str, model_cls=model_cls)
        self.is_source_model_order = False
        if alias:
            self.table_prefix = alias
        if self.source_model == self.target_model and "__" not in self.related_str:
            self.is_source_model_order = True

    @property
    def field_alias(self) -> str:
        return self.target_model.get_column_alias(self.field_name)

    def get_field_name_text(self) -> str:
        """
        Escapes characters if it's required.
        Substitutes values of the models if value is a ormar Model with its pk value.
        Compiles the clause.

        :return: complied and escaped clause
        :rtype: sqlalchemy.sql.elements.TextClause
        """
        prefix = f"{self.table_prefix}_" if self.table_prefix else ""
        return f"{prefix}{self.table}" f".{self.field_alias}"

    def get_min_or_max(self) -> sqlalchemy.sql.expression.TextClause:
        """
        Used in limit sub queries where you need to use aggregated functions
        in order to order by columns not included in group by.

        :return: min or max function to order
        :rtype: sqlalchemy.sql.elements.TextClause
        """
        prefix = f"{self.table_prefix}_" if self.table_prefix else ""
        if self.direction == "":
            return text(f"min({prefix}{self.table}" f".{self.field_alias})")
        return text(f"max({prefix}{self.table}" f".{self.field_alias}) desc")

    def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause:
        """
        Escapes characters if it's required.
        Substitutes values of the models if value is a ormar Model with its pk value.
        Compiles the clause.

        :return: complied and escaped clause
        :rtype: sqlalchemy.sql.elements.TextClause
        """
        prefix = f"{self.table_prefix}_" if self.table_prefix else ""
        table_name = self.table.name
        field_name = self.field_alias
        if not prefix:
            dialect = self.target_model.Meta.database._backend._dialect
            table_name = dialect.identifier_preparer.quote(table_name)
            field_name = dialect.identifier_preparer.quote(field_name)
        return text(f"{prefix}{table_name}" f".{field_name} {self.direction}")

    def _split_value_into_parts(self, order_str: str) -> None:
        if order_str.startswith("-"):
            self.direction = "desc"
            order_str = order_str[1:]
        parts = order_str.split("__")
        self.field_name = parts[-1]
        self.related_parts = parts[:-1]

    def check_if_filter_apply(self, target_model: Type["Model"], alias: str) -> bool:
        """
        Checks filter conditions to find if they apply to current join.

        :param target_model: model which is now processed
        :type target_model: Type["Model"]
        :param alias: prefix of the relation
        :type alias: str
        :return: result of the check
        :rtype: bool
        """
        return target_model == self.target_model and alias == self.table_prefix

check_if_filter_apply(target_model, alias)

Checks filter conditions to find if they apply to current join.

Parameters:

Name Type Description Default
target_model Type['Model']

model which is now processed

required
alias str

prefix of the relation

required

Returns:

Type Description
bool

result of the check

Source code in ormar/queryset/actions/order_action.py
88
89
90
91
92
93
94
95
96
97
98
99
def check_if_filter_apply(self, target_model: Type["Model"], alias: str) -> bool:
    """
    Checks filter conditions to find if they apply to current join.

    :param target_model: model which is now processed
    :type target_model: Type["Model"]
    :param alias: prefix of the relation
    :type alias: str
    :return: result of the check
    :rtype: bool
    """
    return target_model == self.target_model and alias == self.table_prefix

get_field_name_text()

Escapes characters if it's required. Substitutes values of the models if value is a ormar Model with its pk value. Compiles the clause.

Returns:

Type Description
sqlalchemy.sql.elements.TextClause

complied and escaped clause

Source code in ormar/queryset/actions/order_action.py
37
38
39
40
41
42
43
44
45
46
47
def get_field_name_text(self) -> str:
    """
    Escapes characters if it's required.
    Substitutes values of the models if value is a ormar Model with its pk value.
    Compiles the clause.

    :return: complied and escaped clause
    :rtype: sqlalchemy.sql.elements.TextClause
    """
    prefix = f"{self.table_prefix}_" if self.table_prefix else ""
    return f"{prefix}{self.table}" f".{self.field_alias}"

get_min_or_max()

Used in limit sub queries where you need to use aggregated functions in order to order by columns not included in group by.

Returns:

Type Description
sqlalchemy.sql.elements.TextClause

min or max function to order

Source code in ormar/queryset/actions/order_action.py
49
50
51
52
53
54
55
56
57
58
59
60
def get_min_or_max(self) -> sqlalchemy.sql.expression.TextClause:
    """
    Used in limit sub queries where you need to use aggregated functions
    in order to order by columns not included in group by.

    :return: min or max function to order
    :rtype: sqlalchemy.sql.elements.TextClause
    """
    prefix = f"{self.table_prefix}_" if self.table_prefix else ""
    if self.direction == "":
        return text(f"min({prefix}{self.table}" f".{self.field_alias})")
    return text(f"max({prefix}{self.table}" f".{self.field_alias}) desc")

get_text_clause()

Escapes characters if it's required. Substitutes values of the models if value is a ormar Model with its pk value. Compiles the clause.

Returns:

Type Description
sqlalchemy.sql.elements.TextClause

complied and escaped clause

Source code in ormar/queryset/actions/order_action.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause:
    """
    Escapes characters if it's required.
    Substitutes values of the models if value is a ormar Model with its pk value.
    Compiles the clause.

    :return: complied and escaped clause
    :rtype: sqlalchemy.sql.elements.TextClause
    """
    prefix = f"{self.table_prefix}_" if self.table_prefix else ""
    table_name = self.table.name
    field_name = self.field_alias
    if not prefix:
        dialect = self.target_model.Meta.database._backend._dialect
        table_name = dialect.identifier_preparer.quote(table_name)
        field_name = dialect.identifier_preparer.quote(field_name)
    return text(f"{prefix}{table_name}" f".{field_name} {self.direction}")

QuerySet

Bases: Generic[T]

Main class to perform database queries, exposed on each model as objects attribute.

Source code in ormar/queryset/queryset.py
  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
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  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
 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
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 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
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 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
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
class QuerySet(Generic[T]):
    """
    Main class to perform database queries, exposed on each model as objects attribute.
    """

    def __init__(  # noqa CFQ002
        self,
        model_cls: Optional[Type["T"]] = None,
        filter_clauses: List = None,
        exclude_clauses: List = None,
        select_related: List = None,
        limit_count: int = None,
        offset: int = None,
        excludable: "ExcludableItems" = None,
        order_bys: List = None,
        prefetch_related: List = None,
        limit_raw_sql: bool = False,
        proxy_source_model: Optional[Type["Model"]] = None,
    ) -> None:
        self.proxy_source_model = proxy_source_model
        self.model_cls = model_cls
        self.filter_clauses = [] if filter_clauses is None else filter_clauses
        self.exclude_clauses = [] if exclude_clauses is None else exclude_clauses
        self._select_related = [] if select_related is None else select_related
        self._prefetch_related = [] if prefetch_related is None else prefetch_related
        self.limit_count = limit_count
        self.query_offset = offset
        self._excludable = excludable or ormar.ExcludableItems()
        self.order_bys = order_bys or []
        self.limit_sql_raw = limit_raw_sql

    @property
    def model_meta(self) -> "ModelMeta":
        """
        Shortcut to model class Meta set on QuerySet model.

        :return: Meta class of the model
        :rtype: model Meta class
        """
        if not self.model_cls:  # pragma nocover
            raise ValueError("Model class of QuerySet is not initialized")
        return self.model_cls.Meta

    @property
    def model(self) -> Type["T"]:
        """
        Shortcut to model class set on QuerySet.

        :return: model class
        :rtype: Type[Model]
        """
        if not self.model_cls:  # pragma nocover
            raise ValueError("Model class of QuerySet is not initialized")
        return self.model_cls

    def rebuild_self(  # noqa: CFQ002
        self,
        filter_clauses: List = None,
        exclude_clauses: List = None,
        select_related: List = None,
        limit_count: int = None,
        offset: int = None,
        excludable: "ExcludableItems" = None,
        order_bys: List = None,
        prefetch_related: List = None,
        limit_raw_sql: bool = None,
        proxy_source_model: Optional[Type["Model"]] = None,
    ) -> "QuerySet":
        """
        Method that returns new instance of queryset based on passed params,
        all not passed params are taken from current values.
        """
        overwrites = {
            "select_related": "_select_related",
            "offset": "query_offset",
            "excludable": "_excludable",
            "prefetch_related": "_prefetch_related",
            "limit_raw_sql": "limit_sql_raw",
        }
        passed_args = locals()

        def replace_if_none(arg_name: str) -> Any:
            if passed_args.get(arg_name) is None:
                return getattr(self, overwrites.get(arg_name, arg_name))
            return passed_args.get(arg_name)

        return self.__class__(
            model_cls=self.model_cls,
            filter_clauses=replace_if_none("filter_clauses"),
            exclude_clauses=replace_if_none("exclude_clauses"),
            select_related=replace_if_none("select_related"),
            limit_count=replace_if_none("limit_count"),
            offset=replace_if_none("offset"),
            excludable=replace_if_none("excludable"),
            order_bys=replace_if_none("order_bys"),
            prefetch_related=replace_if_none("prefetch_related"),
            limit_raw_sql=replace_if_none("limit_raw_sql"),
            proxy_source_model=replace_if_none("proxy_source_model"),
        )

    async def _prefetch_related_models(
        self, models: List["T"], rows: List
    ) -> List["T"]:
        """
        Performs prefetch query for selected models names.

        :param models: list of already parsed main Models from main query
        :type models: List[Model]
        :param rows: database rows from main query
        :type rows: List[sqlalchemy.engine.result.RowProxy]
        :return: list of models with prefetch models populated
        :rtype: List[Model]
        """
        query = PrefetchQuery(
            model_cls=self.model,
            excludable=self._excludable,
            prefetch_related=self._prefetch_related,
            select_related=self._select_related,
            orders_by=self.order_bys,
        )
        return await query.prefetch_related(models=models, rows=rows)  # type: ignore

    def _process_query_result_rows(self, rows: List) -> List["T"]:
        """
        Process database rows and initialize ormar Model from each of the rows.

        :param rows: list of database rows from query result
        :type rows: List[sqlalchemy.engine.result.RowProxy]
        :return: list of models
        :rtype: List[Model]
        """
        result_rows = [
            self.model.from_row(
                row=row,
                select_related=self._select_related,
                excludable=self._excludable,
                source_model=self.model,
                proxy_source_model=self.proxy_source_model,
            )
            for row in rows
        ]
        if result_rows:
            return self.model.merge_instances_list(result_rows)  # type: ignore
        return cast(List["T"], result_rows)

    def _resolve_filter_groups(
        self, groups: Any
    ) -> Tuple[List[FilterGroup], List[str]]:
        """
        Resolves filter groups to populate FilterAction params in group tree.

        :param groups: tuple of FilterGroups
        :type groups: Any
        :return: list of resolver groups
        :rtype: Tuple[List[FilterGroup], List[str]]
        """
        filter_groups = []
        select_related = self._select_related
        if groups:
            for group in groups:
                if not isinstance(group, FilterGroup):
                    raise QueryDefinitionError(
                        "Only ormar.and_ and ormar.or_ "
                        "can be passed as filter positional"
                        " arguments,"
                        "other values need to be passed by"
                        "keyword arguments"
                    )
                _, select_related = group.resolve(
                    model_cls=self.model,
                    select_related=self._select_related,
                    filter_clauses=self.filter_clauses,
                )
                filter_groups.append(group)
        return filter_groups, select_related

    @staticmethod
    def check_single_result_rows_count(rows: Sequence[Optional["T"]]) -> None:
        """
        Verifies if the result has one and only one row.

        :param rows: one element list of Models
        :type rows: List[Model]
        """
        if not rows or rows[0] is None:
            raise NoMatch()
        if len(rows) > 1:
            raise MultipleMatches()

    @property
    def database(self) -> databases.Database:
        """
        Shortcut to models database from Meta class.

        :return: database
        :rtype: databases.Database
        """
        return self.model_meta.database

    @property
    def table(self) -> sqlalchemy.Table:
        """
        Shortcut to models table from Meta class.

        :return: database table
        :rtype: sqlalchemy.Table
        """
        return self.model_meta.table

    def build_select_expression(
        self, limit: int = None, offset: int = None, order_bys: List = None
    ) -> sqlalchemy.sql.select:
        """
        Constructs the actual database query used in the QuerySet.
        If any of the params is not passed the QuerySet own value is used.

        :param limit: number to limit the query
        :type limit: int
        :param offset: number to offset by
        :type offset: int
        :param order_bys: list of order-by fields names
        :type order_bys: List
        :return: built sqlalchemy select expression
        :rtype: sqlalchemy.sql.selectable.Select
        """
        qry = Query(
            model_cls=self.model,
            select_related=self._select_related,
            filter_clauses=self.filter_clauses,
            exclude_clauses=self.exclude_clauses,
            offset=offset or self.query_offset,
            limit_count=limit or self.limit_count,
            excludable=self._excludable,
            order_bys=order_bys or self.order_bys,
            limit_raw_sql=self.limit_sql_raw,
        )
        exp = qry.build_select_expression()
        # print("\n", exp.compile(compile_kwargs={"literal_binds": True}))
        return exp

    def filter(  # noqa: A003
        self, *args: Any, _exclude: bool = False, **kwargs: Any
    ) -> "QuerySet[T]":
        """
        Allows you to filter by any `Model` attribute/field
        as well as to fetch instances, with a filter across an FK relationship.

        You can use special filter suffix to change the filter operands:

        *  exact - like `album__name__exact='Malibu'` (exact match)
        *  iexact - like `album__name__iexact='malibu'` (exact match case insensitive)
        *  contains - like `album__name__contains='Mal'` (sql like)
        *  icontains - like `album__name__icontains='mal'` (sql like case insensitive)
        *  in - like `album__name__in=['Malibu', 'Barclay']` (sql in)
        *  isnull - like `album__name__isnull=True` (sql is null)
           (isnotnull `album__name__isnull=False` (sql is not null))
        *  gt - like `position__gt=3` (sql >)
        *  gte - like `position__gte=3` (sql >=)
        *  lt - like `position__lt=3` (sql <)
        *  lte - like `position__lte=3` (sql <=)
        *  startswith - like `album__name__startswith='Mal'` (exact start match)
        *  istartswith - like `album__name__istartswith='mal'` (case insensitive)
        *  endswith - like `album__name__endswith='ibu'` (exact end match)
        *  iendswith - like `album__name__iendswith='IBU'` (case insensitive)

        Note that you can also use python style filters - check the docs!

        :param _exclude: flag if it should be exclude or filter
        :type _exclude: bool
        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: filtered QuerySet
        :rtype: QuerySet
        """
        filter_groups, select_related = self._resolve_filter_groups(groups=args)
        qryclause = QueryClause(
            model_cls=self.model,
            select_related=select_related,
            filter_clauses=self.filter_clauses,
        )
        filter_clauses, select_related = qryclause.prepare_filter(**kwargs)
        filter_clauses = filter_clauses + filter_groups  # type: ignore
        if _exclude:
            exclude_clauses = filter_clauses
            filter_clauses = self.filter_clauses
        else:
            exclude_clauses = self.exclude_clauses
            filter_clauses = filter_clauses

        return self.rebuild_self(
            filter_clauses=filter_clauses,
            exclude_clauses=exclude_clauses,
            select_related=select_related,
        )

    def exclude(self, *args: Any, **kwargs: Any) -> "QuerySet[T]":  # noqa: A003
        """
        Works exactly the same as filter and all modifiers (suffixes) are the same,
        but returns a *not* condition.

        So if you use `filter(name='John')` which is `where name = 'John'` in SQL,
        the `exclude(name='John')` equals to `where name <> 'John'`

        Note that all conditions are joined so if you pass multiple values it
        becomes a union of conditions.

        `exclude(name='John', age>=35)` will become
        `where not (name='John' and age>=35)`

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: filtered QuerySet
        :rtype: QuerySet
        """
        return self.filter(_exclude=True, *args, **kwargs)

    def select_related(self, related: Union[List, str, FieldAccessor]) -> "QuerySet[T]":
        """
        Allows to prefetch related models during the same query.

        **With `select_related` always only one query is run against the database**,
        meaning that one (sometimes complicated) join is generated and later nested
        models are processed in python.

        To fetch related model use `ForeignKey` names.

        To chain related `Models` relation use double underscores between names.

        :param related: list of relation field names, can be linked by '__' to nest
        :type related: Union[List, str]
        :return: QuerySet
        :rtype: QuerySet
        """
        if not isinstance(related, list):
            related = [related]
        related = [
            rel._access_chain if isinstance(rel, FieldAccessor) else rel
            for rel in related
        ]

        related = sorted(list(set(list(self._select_related) + related)))
        return self.rebuild_self(select_related=related)

    def select_all(self, follow: bool = False) -> "QuerySet[T]":
        """
        By default adds only directly related models.

        If follow=True is set it adds also related models of related models.

        To not get stuck in an infinite loop as related models also keep a relation
        to parent model visited models set is kept.

        That way already visited models that are nested are loaded, but the load do not
        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.

        :param follow: flag to trigger deep save -
        by default only directly related models are saved
        with follow=True also related models of related models are saved
        :type follow: bool
        :return: reloaded Model
        :rtype: Model
        """
        relations = list(self.model.extract_related_names())
        if follow:
            relations = self.model._iterate_related_models()
        return self.rebuild_self(select_related=relations)

    def prefetch_related(
        self, related: Union[List, str, FieldAccessor]
    ) -> "QuerySet[T]":
        """
        Allows to prefetch related models during query - but opposite to
        `select_related` each subsequent model is fetched in a separate database query.

        **With `prefetch_related` always one query per Model is run against the
        database**, meaning that you will have multiple queries executed one
        after another.

        To fetch related model use `ForeignKey` names.

        To chain related `Models` relation use double underscores between names.

        :param related: list of relation field names, can be linked by '__' to nest
        :type related: Union[List, str]
        :return: QuerySet
        :rtype: QuerySet
        """
        if not isinstance(related, list):
            related = [related]
        related = [
            rel._access_chain if isinstance(rel, FieldAccessor) else rel
            for rel in related
        ]

        related = list(set(list(self._prefetch_related) + related))
        return self.rebuild_self(prefetch_related=related)

    def fields(
        self, columns: Union[List, str, Set, Dict], _is_exclude: bool = False
    ) -> "QuerySet[T]":
        """
        With `fields()` you can select subset of model columns to limit the data load.

        Note that `fields()` and `exclude_fields()` works both for main models
        (on normal queries like `get`, `all` etc.)
        as well as `select_related` and `prefetch_related`
        models (with nested notation).

        You can select specified fields by passing a `str, List[str], Set[str] or
        dict` with nested definition.

        To include related models use notation
        `{related_name}__{column}[__{optional_next} etc.]`.

        `fields()` can be called several times, building up the columns to select.

        If you include related models into `select_related()` call but you won't specify
        columns for those models in fields - implies a list of all fields for
        those nested models.

        Mandatory fields cannot be excluded as it will raise `ValidationError`,
        to exclude a field it has to be nullable.

        Pk column cannot be excluded - it's always auto added even if
        not explicitly included.

        You can also pass fields to include as dictionary or set.

        To mark a field as included in a dictionary use it's name as key
        and ellipsis as value.

        To traverse nested models use nested dictionaries.

        To include fields at last level instead of nested dictionary a set can be used.

        To include whole nested model specify model related field name and ellipsis.

        :param _is_exclude: flag if it's exclude or include operation
        :type _is_exclude: bool
        :param columns: columns to include
        :type columns: Union[List, str, Set, Dict]
        :return: QuerySet
        :rtype: QuerySet
        """
        excludable = ormar.ExcludableItems.from_excludable(self._excludable)
        excludable.build(
            items=columns,
            model_cls=self.model_cls,  # type: ignore
            is_exclude=_is_exclude,
        )

        return self.rebuild_self(excludable=excludable)

    def exclude_fields(self, columns: Union[List, str, Set, Dict]) -> "QuerySet[T]":
        """
        With `exclude_fields()` you can select subset of model columns that will
        be excluded to limit the data load.

        It's the opposite of `fields()` method so check documentation above
        to see what options are available.

        Especially check above how you can pass also nested dictionaries
        and sets as a mask to exclude fields from whole hierarchy.

        Note that `fields()` and `exclude_fields()` works both for main models
        (on normal queries like `get`, `all` etc.)
        as well as `select_related` and `prefetch_related` models
        (with nested notation).

        Mandatory fields cannot be excluded as it will raise `ValidationError`,
        to exclude a field it has to be nullable.

        Pk column cannot be excluded - it's always auto added even
        if explicitly excluded.

        :param columns: columns to exclude
        :type columns: Union[List, str, Set, Dict]
        :return: QuerySet
        :rtype: QuerySet
        """
        return self.fields(columns=columns, _is_exclude=True)

    def order_by(self, columns: Union[List, str, OrderAction]) -> "QuerySet[T]":
        """
        With `order_by()` you can order the results from database based on your
        choice of fields.

        You can provide a string with field name or list of strings with fields names.

        Ordering in sql will be applied in order of names you provide in order_by.

        By default if you do not provide ordering `ormar` explicitly orders by
        all primary keys

        If you are sorting by nested models that causes that the result rows are
        unsorted by the main model `ormar` will combine those children rows into
        one main model.

        The main model will never duplicate in the result

        To order by main model field just provide a field name

        To sort on nested models separate field names with dunder '__'.

        You can sort this way across all relation types -> `ForeignKey`,
        reverse virtual FK and `ManyToMany` fields.

        To sort in descending order provide a hyphen in front of the field name

        :param columns: columns by which models should be sorted
        :type columns: Union[List, str]
        :return: QuerySet
        :rtype: QuerySet
        """
        if not isinstance(columns, list):
            columns = [columns]

        orders_by = [
            OrderAction(order_str=x, model_cls=self.model_cls)  # type: ignore
            if not isinstance(x, OrderAction)
            else x
            for x in columns
        ]

        order_bys = self.order_bys + [x for x in orders_by if x not in self.order_bys]
        return self.rebuild_self(order_bys=order_bys)

    async def values(
        self,
        fields: Union[List, str, Set, Dict] = None,
        exclude_through: bool = False,
        _as_dict: bool = True,
        _flatten: bool = False,
    ) -> List:
        """
        Return a list of dictionaries with column values in order of the fields
        passed or all fields from queried models.

        To filter for given row use filter/exclude methods before values,
        to limit number of rows use limit/offset or paginate before values.

        Note that it always return a list even for one row from database.

        :param exclude_through: flag if through models should be excluded
        :type exclude_through: bool
        :param _flatten: internal parameter to flatten one element tuples
        :type _flatten: bool
        :param _as_dict: internal parameter if return dict or tuples
        :type _as_dict: bool
        :param fields: field name or list of field names to extract from db
        :type fields:  Union[List, str, Set, Dict]
        """
        if fields:
            return await self.fields(columns=fields).values(
                _as_dict=_as_dict, _flatten=_flatten, exclude_through=exclude_through
            )
        expr = self.build_select_expression()
        rows = await self.database.fetch_all(expr)
        if not rows:
            return []
        alias_resolver = ReverseAliasResolver(
            select_related=self._select_related,
            excludable=self._excludable,
            model_cls=self.model_cls,  # type: ignore
            exclude_through=exclude_through,
        )
        column_map = alias_resolver.resolve_columns(
            columns_names=list(cast(LegacyRow, rows[0]).keys())
        )
        result = [
            {column_map.get(k): v for k, v in dict(x).items() if k in column_map}
            for x in rows
        ]
        if _as_dict:
            return result
        if _flatten and self._excludable.include_entry_count() != 1:
            raise QueryDefinitionError(
                "You cannot flatten values_list if more than one field is selected!"
            )
        tuple_result = [tuple(x.values()) for x in result]
        return tuple_result if not _flatten else [x[0] for x in tuple_result]

    async def values_list(
        self,
        fields: Union[List, str, Set, Dict] = None,
        flatten: bool = False,
        exclude_through: bool = False,
    ) -> List:
        """
        Return a list of tuples with column values in order of the fields passed or
        all fields from queried models.

        When one field is passed you can flatten the list of tuples into list of values
        of that single field.

        To filter for given row use filter/exclude methods before values,
        to limit number of rows use limit/offset or paginate before values.

        Note that it always return a list even for one row from database.

        :param exclude_through: flag if through models should be excluded
        :type exclude_through: bool
        :param fields: field name or list of field names to extract from db
        :type fields: Union[str, List[str]]
        :param flatten: when one field is passed you can flatten the list of tuples
        :type flatten: bool
        """
        return await self.values(
            fields=fields,
            exclude_through=exclude_through,
            _as_dict=False,
            _flatten=flatten,
        )

    async def exists(self) -> bool:
        """
        Returns a bool value to confirm if there are rows matching the given criteria
        (applied with `filter` and `exclude` if set).

        :return: result of the check
        :rtype: bool
        """
        expr = self.build_select_expression()
        expr = sqlalchemy.exists(expr).select()
        return await self.database.fetch_val(expr)

    async def count(self, distinct: bool = True) -> int:
        """
        Returns number of rows matching the given criteria
        (applied with `filter` and `exclude` if set before).
        If `distinct` is `True` (the default), this will return
        the number of primary rows selected. If `False`,
        the count will be the total number of rows returned
        (including extra rows for `one-to-many` or `many-to-many`
        left `select_related` table joins).
        `False` is the legacy (buggy) behavior for workflows that depend on it.

        :param distinct: flag if the primary table rows should be distinct or not

        :return: number of rows
        :rtype: int
        """
        expr = self.build_select_expression().alias("subquery_for_count")
        expr = sqlalchemy.func.count().select().select_from(expr)
        if distinct:
            pk_column_name = self.model.get_column_alias(self.model_meta.pkname)
            expr_distinct = expr.group_by(pk_column_name).alias("subquery_for_group")
            expr = sqlalchemy.func.count().select().select_from(expr_distinct)
        return await self.database.fetch_val(expr)

    async def _query_aggr_function(self, func_name: str, columns: List) -> Any:
        func = getattr(sqlalchemy.func, func_name)
        select_actions = [
            SelectAction(select_str=column, model_cls=self.model) for column in columns
        ]
        if func_name in ["sum", "avg"]:
            if any(not x.is_numeric for x in select_actions):
                raise QueryDefinitionError(
                    "You can use sum and svg only with" "numeric types of columns"
                )
        select_columns = [x.apply_func(func, use_label=True) for x in select_actions]
        expr = self.build_select_expression().alias(f"subquery_for_{func_name}")
        expr = sqlalchemy.select(select_columns).select_from(expr)
        # print("\n", expr.compile(compile_kwargs={"literal_binds": True}))
        result = await self.database.fetch_one(expr)
        return dict(result) if len(result) > 1 else result[0]  # type: ignore

    async def max(self, columns: Union[str, List[str]]) -> Any:  # noqa: A003
        """
        Returns max value of columns for rows matching the given criteria
        (applied with `filter` and `exclude` if set before).

        :return: max value of column(s)
        :rtype: Any
        """
        if not isinstance(columns, list):
            columns = [columns]
        return await self._query_aggr_function(func_name="max", columns=columns)

    async def min(self, columns: Union[str, List[str]]) -> Any:  # noqa: A003
        """
        Returns min value of columns for rows matching the given criteria
        (applied with `filter` and `exclude` if set before).

        :return: min value of column(s)
        :rtype: Any
        """
        if not isinstance(columns, list):
            columns = [columns]
        return await self._query_aggr_function(func_name="min", columns=columns)

    async def sum(self, columns: Union[str, List[str]]) -> Any:  # noqa: A003
        """
        Returns sum value of columns for rows matching the given criteria
        (applied with `filter` and `exclude` if set before).

        :return: sum value of columns
        :rtype: int
        """
        if not isinstance(columns, list):
            columns = [columns]
        return await self._query_aggr_function(func_name="sum", columns=columns)

    async def avg(self, columns: Union[str, List[str]]) -> Any:
        """
        Returns avg value of columns for rows matching the given criteria
        (applied with `filter` and `exclude` if set before).

        :return: avg value of columns
        :rtype: Union[int, float, List]
        """
        if not isinstance(columns, list):
            columns = [columns]
        return await self._query_aggr_function(func_name="avg", columns=columns)

    async def update(self, each: bool = False, **kwargs: Any) -> int:
        """
        Updates the model table after applying the filters from kwargs.

        You have to either pass a filter to narrow down a query or explicitly pass
        each=True flag to affect whole table.

        :param each: flag if whole table should be affected if no filter is passed
        :type each: bool
        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: number of updated rows
        :rtype: int
        """
        if not each and not (self.filter_clauses or self.exclude_clauses):
            raise QueryDefinitionError(
                "You cannot update without filtering the queryset first. "
                "If you want to update all rows use update(each=True, **kwargs)"
            )

        self_fields = self.model.extract_db_own_fields().union(
            self.model.extract_related_names()
        )
        updates = {k: v for k, v in kwargs.items() if k in self_fields}
        updates = self.model.validate_choices(updates)
        updates = self.model.translate_columns_to_aliases(updates)

        expr = FilterQuery(filter_clauses=self.filter_clauses).apply(
            self.table.update().values(**updates)
        )
        expr = FilterQuery(filter_clauses=self.exclude_clauses, exclude=True).apply(
            expr
        )
        return await self.database.execute(expr)

    async def delete(self, *args: Any, each: bool = False, **kwargs: Any) -> int:
        """
        Deletes from the model table after applying the filters from kwargs.

        You have to either pass a filter to narrow down a query or explicitly pass
        each=True flag to affect whole table.

        :param each: flag if whole table should be affected if no filter is passed
        :type each: bool
        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: number of deleted rows
        :rtype:int
        """
        if kwargs or args:
            return await self.filter(*args, **kwargs).delete()
        if not each and not (self.filter_clauses or self.exclude_clauses):
            raise QueryDefinitionError(
                "You cannot delete without filtering the queryset first. "
                "If you want to delete all rows use delete(each=True)"
            )
        expr = FilterQuery(filter_clauses=self.filter_clauses).apply(
            self.table.delete()
        )
        expr = FilterQuery(filter_clauses=self.exclude_clauses, exclude=True).apply(
            expr
        )
        return await self.database.execute(expr)

    def paginate(self, page: int, page_size: int = 20) -> "QuerySet[T]":
        """
        You can paginate the result which is a combination of offset and limit clauses.
        Limit is set to page size and offset is set to (page-1) * page_size.

        :param page_size: numbers of items per page
        :type page_size: int
        :param page: page number
        :type page: int
        :return: QuerySet
        :rtype: QuerySet
        """
        if page < 1 or page_size < 1:
            raise QueryDefinitionError("Page size and page have to be greater than 0.")

        limit_count = page_size
        query_offset = (page - 1) * page_size
        return self.rebuild_self(limit_count=limit_count, offset=query_offset)

    def limit(self, limit_count: int, limit_raw_sql: bool = None) -> "QuerySet[T]":
        """
        You can limit the results to desired number of parent models.

        To limit the actual number of database query rows instead of number of main
        models use the `limit_raw_sql` parameter flag, and set it to `True`.

        :param limit_raw_sql: flag if raw sql should be limited
        :type limit_raw_sql: bool
        :param limit_count: number of models to limit
        :type limit_count: int
        :return: QuerySet
        :rtype: QuerySet
        """
        limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql
        return self.rebuild_self(limit_count=limit_count, limit_raw_sql=limit_raw_sql)

    def offset(self, offset: int, limit_raw_sql: bool = None) -> "QuerySet[T]":
        """
        You can also offset the results by desired number of main models.

        To offset the actual number of database query rows instead of number of main
        models use the `limit_raw_sql` parameter flag, and set it to `True`.

        :param limit_raw_sql: flag if raw sql should be offset
        :type limit_raw_sql: bool
        :param offset: numbers of models to offset
        :type offset: int
        :return: QuerySet
        :rtype: QuerySet
        """
        limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql
        return self.rebuild_self(offset=offset, limit_raw_sql=limit_raw_sql)

    async def first(self, *args: Any, **kwargs: Any) -> "T":
        """
        Gets the first row from the db ordered by primary key column ascending.

        :raises NoMatch: if no rows are returned
        :raises MultipleMatches: if more than 1 row is returned.
        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: returned model
        :rtype: Model
        """
        if kwargs or args:
            return await self.filter(*args, **kwargs).first()

        expr = self.build_select_expression(
            limit=1,
            order_bys=(
                [
                    OrderAction(
                        order_str=f"{self.model.Meta.pkname}",
                        model_cls=self.model_cls,  # type: ignore
                    )
                ]
                if not any([x.is_source_model_order for x in self.order_bys])
                else []
            )
            + self.order_bys,
        )
        rows = await self.database.fetch_all(expr)
        processed_rows = self._process_query_result_rows(rows)
        if self._prefetch_related and processed_rows:
            processed_rows = await self._prefetch_related_models(processed_rows, rows)
        self.check_single_result_rows_count(processed_rows)
        return processed_rows[0]  # type: ignore

    async def get_or_none(self, *args: Any, **kwargs: Any) -> Optional["T"]:
        """
        Get's the first row from the db meeting the criteria set by kwargs.

        If no criteria set it will return the last row in db sorted by pk.

        Passing a criteria is actually calling filter(*args, **kwargs) method described
        below.

        If not match is found None will be returned.

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: returned model
        :rtype: Model
        """
        try:
            return await self.get(*args, **kwargs)
        except ormar.NoMatch:
            return None

    async def get(self, *args: Any, **kwargs: Any) -> "T":  # noqa: CCR001
        """
        Get's the first row from the db meeting the criteria set by kwargs.

        If no criteria set it will return the last row in db sorted by pk.

        Passing a criteria is actually calling filter(*args, **kwargs) method described
        below.

        :raises NoMatch: if no rows are returned
        :raises MultipleMatches: if more than 1 row is returned.
        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: returned model
        :rtype: Model
        """
        if kwargs or args:
            return await self.filter(*args, **kwargs).get()

        if not self.filter_clauses:
            expr = self.build_select_expression(
                limit=1,
                order_bys=(
                    [
                        OrderAction(
                            order_str=f"-{self.model.Meta.pkname}",
                            model_cls=self.model_cls,  # type: ignore
                        )
                    ]
                    if not any([x.is_source_model_order for x in self.order_bys])
                    else []
                )
                + self.order_bys,
            )
        else:
            expr = self.build_select_expression()

        rows = await self.database.fetch_all(expr)
        processed_rows = self._process_query_result_rows(rows)
        if self._prefetch_related and processed_rows:
            processed_rows = await self._prefetch_related_models(processed_rows, rows)
        self.check_single_result_rows_count(processed_rows)
        return processed_rows[0]  # type: ignore

    async def get_or_create(
        self,
        _defaults: Optional[Dict[str, Any]] = None,
        *args: Any,
        **kwargs: Any,
    ) -> Tuple["T", bool]:
        """
        Combination of create and get methods.

        Tries to get a row meeting the criteria for kwargs
        and if `NoMatch` exception is raised
        it creates a new one with given kwargs and _defaults.

        Passing a criteria is actually calling filter(*args, **kwargs) method described
        below.

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :param _defaults: default values for creating object
        :type _defaults: Optional[Dict[str, Any]]
        :return: model instance and a boolean
        :rtype: Tuple("T", bool)
        """
        try:
            return await self.get(*args, **kwargs), False
        except NoMatch:
            _defaults = _defaults or {}
            return await self.create(**{**kwargs, **_defaults}), True

    async def update_or_create(self, **kwargs: Any) -> "T":
        """
        Updates the model, or in case there is no match in database creates a new one.

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: updated or created model
        :rtype: Model
        """
        pk_name = self.model_meta.pkname
        if "pk" in kwargs:
            kwargs[pk_name] = kwargs.pop("pk")
        if pk_name not in kwargs or kwargs.get(pk_name) is None:
            return await self.create(**kwargs)
        model = await self.get(pk=kwargs[pk_name])
        return await model.update(**kwargs)

    async def all(self, *args: Any, **kwargs: Any) -> List["T"]:  # noqa: A003
        """
        Returns all rows from a database for given model for set filter options.

        Passing args and/or kwargs is a shortcut and equals to calling
        `filter(*args, **kwargs).all()`.

        If there are no rows meeting the criteria an empty list is returned.

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: list of returned models
        :rtype: List[Model]
        """
        if kwargs or args:
            return await self.filter(*args, **kwargs).all()

        expr = self.build_select_expression()
        rows = await self.database.fetch_all(expr)
        result_rows = self._process_query_result_rows(rows)
        if self._prefetch_related and result_rows:
            result_rows = await self._prefetch_related_models(result_rows, rows)

        return result_rows

    async def create(self, **kwargs: Any) -> "T":
        """
        Creates the model instance, saves it in a database and returns the updates model
        (with pk populated if not passed and autoincrement is set).

        The allowed kwargs are `Model` fields names and proper value types.

        :param kwargs: fields names and proper value types
        :type kwargs: Any
        :return: created model
        :rtype: Model
        """
        instance = self.model(**kwargs)
        instance = await instance.save()
        return instance

    async def bulk_create(self, objects: List["T"]) -> None:
        """
        Performs a bulk create in one database session to speed up the process.

        Allows you to create multiple objects at once.

        A valid list of `Model` objects needs to be passed.

        Bulk operations do not send signals.

        :param objects: list of ormar models already initialized and ready to save.
        :type objects: List[Model]
        """
        ready_objects = [obj.prepare_model_to_save(obj.dict()) for obj in objects]

        # don't use execute_many, as in databases it's executed in a loop
        # instead of using execute_many from drivers
        expr = self.table.insert().values(ready_objects)
        await self.database.execute(expr)

        for obj in objects:
            obj.set_save_status(True)

    async def bulk_update(  # noqa:  CCR001
        self, objects: List["T"], columns: List[str] = None
    ) -> None:
        """
        Performs bulk update in one database session to speed up the process.

        Allows you to update multiple instance at once.

        All `Models` passed need to have primary key column populated.

        You can also select which fields to update by passing `columns` list
        as a list of string names.

        Bulk operations do not send signals.

        :param objects: list of ormar models
        :type objects: List[Model]
        :param columns: list of columns to update
        :type columns: List[str]
        """
        if not objects:
            raise ModelListEmptyError("Bulk update objects are empty!")

        ready_objects = []
        pk_name = self.model_meta.pkname
        if not columns:
            columns = list(
                self.model.extract_db_own_fields().union(
                    self.model.extract_related_names()
                )
            )

        if pk_name not in columns:
            columns.append(pk_name)

        columns = [self.model.get_column_alias(k) for k in columns]

        for obj in objects:
            new_kwargs = obj.dict()
            if new_kwargs.get(pk_name) is None:
                raise ModelPersistenceError(
                    "You cannot update unsaved objects. "
                    f"{self.model.__name__} has to have {pk_name} filled."
                )
            new_kwargs = obj.prepare_model_to_update(new_kwargs)
            ready_objects.append(
                {"new_" + k: v for k, v in new_kwargs.items() if k in columns}
            )

        pk_column = self.model_meta.table.c.get(self.model.get_column_alias(pk_name))
        pk_column_name = self.model.get_column_alias(pk_name)
        table_columns = [c.name for c in self.model_meta.table.c]
        expr = self.table.update().where(
            pk_column == bindparam("new_" + pk_column_name)
        )
        expr = expr.values(
            **{
                k: bindparam("new_" + k)
                for k in columns
                if k != pk_column_name and k in table_columns
            }
        )
        # databases bind params only where query is passed as string
        # otherwise it just passes all data to values and results in unconsumed columns
        expr = str(expr)
        await self.database.execute_many(expr, ready_objects)

        for obj in objects:
            obj.set_save_status(True)

        await cast(Type["Model"], self.model_cls).Meta.signals.post_bulk_update.send(
            sender=self.model_cls, instances=objects  # type: ignore
        )

Performs prefetch query for selected models names.

Parameters:

Name Type Description Default
models List['T']

list of already parsed main Models from main query

required
rows List

database rows from main query

required

Returns:

Type Description
List[Model]

list of models with prefetch models populated

Source code in ormar/queryset/queryset.py
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
async def _prefetch_related_models(
    self, models: List["T"], rows: List
) -> List["T"]:
    """
    Performs prefetch query for selected models names.

    :param models: list of already parsed main Models from main query
    :type models: List[Model]
    :param rows: database rows from main query
    :type rows: List[sqlalchemy.engine.result.RowProxy]
    :return: list of models with prefetch models populated
    :rtype: List[Model]
    """
    query = PrefetchQuery(
        model_cls=self.model,
        excludable=self._excludable,
        prefetch_related=self._prefetch_related,
        select_related=self._select_related,
        orders_by=self.order_bys,
    )
    return await query.prefetch_related(models=models, rows=rows)  # type: ignore

_process_query_result_rows(rows)

Process database rows and initialize ormar Model from each of the rows.

Parameters:

Name Type Description Default
rows List

list of database rows from query result

required

Returns:

Type Description
List[Model]

list of models

Source code in ormar/queryset/queryset.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def _process_query_result_rows(self, rows: List) -> List["T"]:
    """
    Process database rows and initialize ormar Model from each of the rows.

    :param rows: list of database rows from query result
    :type rows: List[sqlalchemy.engine.result.RowProxy]
    :return: list of models
    :rtype: List[Model]
    """
    result_rows = [
        self.model.from_row(
            row=row,
            select_related=self._select_related,
            excludable=self._excludable,
            source_model=self.model,
            proxy_source_model=self.proxy_source_model,
        )
        for row in rows
    ]
    if result_rows:
        return self.model.merge_instances_list(result_rows)  # type: ignore
    return cast(List["T"], result_rows)

_resolve_filter_groups(groups)

Resolves filter groups to populate FilterAction params in group tree.

Parameters:

Name Type Description Default
groups Any

tuple of FilterGroups

required

Returns:

Type Description
Tuple[List[FilterGroup], List[str]]

list of resolver groups

Source code in ormar/queryset/queryset.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
def _resolve_filter_groups(
    self, groups: Any
) -> Tuple[List[FilterGroup], List[str]]:
    """
    Resolves filter groups to populate FilterAction params in group tree.

    :param groups: tuple of FilterGroups
    :type groups: Any
    :return: list of resolver groups
    :rtype: Tuple[List[FilterGroup], List[str]]
    """
    filter_groups = []
    select_related = self._select_related
    if groups:
        for group in groups:
            if not isinstance(group, FilterGroup):
                raise QueryDefinitionError(
                    "Only ormar.and_ and ormar.or_ "
                    "can be passed as filter positional"
                    " arguments,"
                    "other values need to be passed by"
                    "keyword arguments"
                )
            _, select_related = group.resolve(
                model_cls=self.model,
                select_related=self._select_related,
                filter_clauses=self.filter_clauses,
            )
            filter_groups.append(group)
    return filter_groups, select_related

all(*args, **kwargs) async

Returns all rows from a database for given model for set filter options.

Passing args and/or kwargs is a shortcut and equals to calling filter(*args, **kwargs).all().

If there are no rows meeting the criteria an empty list is returned.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
List[Model]

list of returned models

Source code in ormar/queryset/queryset.py
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
async def all(self, *args: Any, **kwargs: Any) -> List["T"]:  # noqa: A003
    """
    Returns all rows from a database for given model for set filter options.

    Passing args and/or kwargs is a shortcut and equals to calling
    `filter(*args, **kwargs).all()`.

    If there are no rows meeting the criteria an empty list is returned.

    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: list of returned models
    :rtype: List[Model]
    """
    if kwargs or args:
        return await self.filter(*args, **kwargs).all()

    expr = self.build_select_expression()
    rows = await self.database.fetch_all(expr)
    result_rows = self._process_query_result_rows(rows)
    if self._prefetch_related and result_rows:
        result_rows = await self._prefetch_related_models(result_rows, rows)

    return result_rows

avg(columns) async

Returns avg value of columns for rows matching the given criteria (applied with filter and exclude if set before).

Returns:

Type Description
Union[int, float, List]

avg value of columns

Source code in ormar/queryset/queryset.py
758
759
760
761
762
763
764
765
766
767
768
async def avg(self, columns: Union[str, List[str]]) -> Any:
    """
    Returns avg value of columns for rows matching the given criteria
    (applied with `filter` and `exclude` if set before).

    :return: avg value of columns
    :rtype: Union[int, float, List]
    """
    if not isinstance(columns, list):
        columns = [columns]
    return await self._query_aggr_function(func_name="avg", columns=columns)

build_select_expression(limit=None, offset=None, order_bys=None)

Constructs the actual database query used in the QuerySet. If any of the params is not passed the QuerySet own value is used.

Parameters:

Name Type Description Default
limit int

number to limit the query

None
offset int

number to offset by

None
order_bys List

list of order-by fields names

None

Returns:

Type Description
sqlalchemy.sql.selectable.Select

built sqlalchemy select expression

Source code in ormar/queryset/queryset.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
def build_select_expression(
    self, limit: int = None, offset: int = None, order_bys: List = None
) -> sqlalchemy.sql.select:
    """
    Constructs the actual database query used in the QuerySet.
    If any of the params is not passed the QuerySet own value is used.

    :param limit: number to limit the query
    :type limit: int
    :param offset: number to offset by
    :type offset: int
    :param order_bys: list of order-by fields names
    :type order_bys: List
    :return: built sqlalchemy select expression
    :rtype: sqlalchemy.sql.selectable.Select
    """
    qry = Query(
        model_cls=self.model,
        select_related=self._select_related,
        filter_clauses=self.filter_clauses,
        exclude_clauses=self.exclude_clauses,
        offset=offset or self.query_offset,
        limit_count=limit or self.limit_count,
        excludable=self._excludable,
        order_bys=order_bys or self.order_bys,
        limit_raw_sql=self.limit_sql_raw,
    )
    exp = qry.build_select_expression()
    # print("\n", exp.compile(compile_kwargs={"literal_binds": True}))
    return exp

bulk_create(objects) async

Performs a bulk create in one database session to speed up the process.

Allows you to create multiple objects at once.

A valid list of Model objects needs to be passed.

Bulk operations do not send signals.

Parameters:

Name Type Description Default
objects List['T']

list of ormar models already initialized and ready to save.

required
Source code in ormar/queryset/queryset.py
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
async def bulk_create(self, objects: List["T"]) -> None:
    """
    Performs a bulk create in one database session to speed up the process.

    Allows you to create multiple objects at once.

    A valid list of `Model` objects needs to be passed.

    Bulk operations do not send signals.

    :param objects: list of ormar models already initialized and ready to save.
    :type objects: List[Model]
    """
    ready_objects = [obj.prepare_model_to_save(obj.dict()) for obj in objects]

    # don't use execute_many, as in databases it's executed in a loop
    # instead of using execute_many from drivers
    expr = self.table.insert().values(ready_objects)
    await self.database.execute(expr)

    for obj in objects:
        obj.set_save_status(True)

bulk_update(objects, columns=None) async

Performs bulk update in one database session to speed up the process.

Allows you to update multiple instance at once.

All Models passed need to have primary key column populated.

You can also select which fields to update by passing columns list as a list of string names.

Bulk operations do not send signals.

Parameters:

Name Type Description Default
objects List['T']

list of ormar models

required
columns List[str]

list of columns to update

None
Source code in ormar/queryset/queryset.py
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
async def bulk_update(  # noqa:  CCR001
    self, objects: List["T"], columns: List[str] = None
) -> None:
    """
    Performs bulk update in one database session to speed up the process.

    Allows you to update multiple instance at once.

    All `Models` passed need to have primary key column populated.

    You can also select which fields to update by passing `columns` list
    as a list of string names.

    Bulk operations do not send signals.

    :param objects: list of ormar models
    :type objects: List[Model]
    :param columns: list of columns to update
    :type columns: List[str]
    """
    if not objects:
        raise ModelListEmptyError("Bulk update objects are empty!")

    ready_objects = []
    pk_name = self.model_meta.pkname
    if not columns:
        columns = list(
            self.model.extract_db_own_fields().union(
                self.model.extract_related_names()
            )
        )

    if pk_name not in columns:
        columns.append(pk_name)

    columns = [self.model.get_column_alias(k) for k in columns]

    for obj in objects:
        new_kwargs = obj.dict()
        if new_kwargs.get(pk_name) is None:
            raise ModelPersistenceError(
                "You cannot update unsaved objects. "
                f"{self.model.__name__} has to have {pk_name} filled."
            )
        new_kwargs = obj.prepare_model_to_update(new_kwargs)
        ready_objects.append(
            {"new_" + k: v for k, v in new_kwargs.items() if k in columns}
        )

    pk_column = self.model_meta.table.c.get(self.model.get_column_alias(pk_name))
    pk_column_name = self.model.get_column_alias(pk_name)
    table_columns = [c.name for c in self.model_meta.table.c]
    expr = self.table.update().where(
        pk_column == bindparam("new_" + pk_column_name)
    )
    expr = expr.values(
        **{
            k: bindparam("new_" + k)
            for k in columns
            if k != pk_column_name and k in table_columns
        }
    )
    # databases bind params only where query is passed as string
    # otherwise it just passes all data to values and results in unconsumed columns
    expr = str(expr)
    await self.database.execute_many(expr, ready_objects)

    for obj in objects:
        obj.set_save_status(True)

    await cast(Type["Model"], self.model_cls).Meta.signals.post_bulk_update.send(
        sender=self.model_cls, instances=objects  # type: ignore
    )

check_single_result_rows_count(rows) staticmethod

Verifies if the result has one and only one row.

Parameters:

Name Type Description Default
rows Sequence[Optional['T']]

one element list of Models

required
Source code in ormar/queryset/queryset.py
229
230
231
232
233
234
235
236
237
238
239
240
@staticmethod
def check_single_result_rows_count(rows: Sequence[Optional["T"]]) -> None:
    """
    Verifies if the result has one and only one row.

    :param rows: one element list of Models
    :type rows: List[Model]
    """
    if not rows or rows[0] is None:
        raise NoMatch()
    if len(rows) > 1:
        raise MultipleMatches()

count(distinct=True) async

Returns number of rows matching the given criteria (applied with filter and exclude if set before). If distinct is True (the default), this will return the number of primary rows selected. If False, the count will be the total number of rows returned (including extra rows for one-to-many or many-to-many left select_related table joins). False is the legacy (buggy) behavior for workflows that depend on it.

Parameters:

Name Type Description Default
distinct bool

flag if the primary table rows should be distinct or not

True

Returns:

Type Description
int

number of rows

Source code in ormar/queryset/queryset.py
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
async def count(self, distinct: bool = True) -> int:
    """
    Returns number of rows matching the given criteria
    (applied with `filter` and `exclude` if set before).
    If `distinct` is `True` (the default), this will return
    the number of primary rows selected. If `False`,
    the count will be the total number of rows returned
    (including extra rows for `one-to-many` or `many-to-many`
    left `select_related` table joins).
    `False` is the legacy (buggy) behavior for workflows that depend on it.

    :param distinct: flag if the primary table rows should be distinct or not

    :return: number of rows
    :rtype: int
    """
    expr = self.build_select_expression().alias("subquery_for_count")
    expr = sqlalchemy.func.count().select().select_from(expr)
    if distinct:
        pk_column_name = self.model.get_column_alias(self.model_meta.pkname)
        expr_distinct = expr.group_by(pk_column_name).alias("subquery_for_group")
        expr = sqlalchemy.func.count().select().select_from(expr_distinct)
    return await self.database.fetch_val(expr)

create(**kwargs) async

Creates the model instance, saves it in a database and returns the updates model (with pk populated if not passed and autoincrement is set).

The allowed kwargs are Model fields names and proper value types.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
Model

created model

Source code in ormar/queryset/queryset.py
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
async def create(self, **kwargs: Any) -> "T":
    """
    Creates the model instance, saves it in a database and returns the updates model
    (with pk populated if not passed and autoincrement is set).

    The allowed kwargs are `Model` fields names and proper value types.

    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: created model
    :rtype: Model
    """
    instance = self.model(**kwargs)
    instance = await instance.save()
    return instance

database() property

Shortcut to models database from Meta class.

Returns:

Type Description
databases.Database

database

Source code in ormar/queryset/queryset.py
242
243
244
245
246
247
248
249
250
@property
def database(self) -> databases.Database:
    """
    Shortcut to models database from Meta class.

    :return: database
    :rtype: databases.Database
    """
    return self.model_meta.database

delete(*args, each=False, **kwargs) async

Deletes from the model table after applying the filters from kwargs.

You have to either pass a filter to narrow down a query or explicitly pass each=True flag to affect whole table.

Parameters:

Name Type Description Default
each bool

flag if whole table should be affected if no filter is passed

False
kwargs Any

fields names and proper value types

required

Returns:

Type Description
int

number of deleted rows

Source code in ormar/queryset/queryset.py
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
async def delete(self, *args: Any, each: bool = False, **kwargs: Any) -> int:
    """
    Deletes from the model table after applying the filters from kwargs.

    You have to either pass a filter to narrow down a query or explicitly pass
    each=True flag to affect whole table.

    :param each: flag if whole table should be affected if no filter is passed
    :type each: bool
    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: number of deleted rows
    :rtype:int
    """
    if kwargs or args:
        return await self.filter(*args, **kwargs).delete()
    if not each and not (self.filter_clauses or self.exclude_clauses):
        raise QueryDefinitionError(
            "You cannot delete without filtering the queryset first. "
            "If you want to delete all rows use delete(each=True)"
        )
    expr = FilterQuery(filter_clauses=self.filter_clauses).apply(
        self.table.delete()
    )
    expr = FilterQuery(filter_clauses=self.exclude_clauses, exclude=True).apply(
        expr
    )
    return await self.database.execute(expr)

exclude(*args, **kwargs)

Works exactly the same as filter and all modifiers (suffixes) are the same, but returns a not condition.

So if you use filter(name='John') which is where name = 'John' in SQL, the exclude(name='John') equals to where name <> 'John'

Note that all conditions are joined so if you pass multiple values it becomes a union of conditions.

exclude(name='John', age>=35) will become where not (name='John' and age>=35)

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
QuerySet

filtered QuerySet

Source code in ormar/queryset/queryset.py
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
def exclude(self, *args: Any, **kwargs: Any) -> "QuerySet[T]":  # noqa: A003
    """
    Works exactly the same as filter and all modifiers (suffixes) are the same,
    but returns a *not* condition.

    So if you use `filter(name='John')` which is `where name = 'John'` in SQL,
    the `exclude(name='John')` equals to `where name <> 'John'`

    Note that all conditions are joined so if you pass multiple values it
    becomes a union of conditions.

    `exclude(name='John', age>=35)` will become
    `where not (name='John' and age>=35)`

    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: filtered QuerySet
    :rtype: QuerySet
    """
    return self.filter(_exclude=True, *args, **kwargs)

exclude_fields(columns)

With exclude_fields() you can select subset of model columns that will be excluded to limit the data load.

It's the opposite of fields() method so check documentation above to see what options are available.

Especially check above how you can pass also nested dictionaries and sets as a mask to exclude fields from whole hierarchy.

Note that fields() and exclude_fields() works both for main models (on normal queries like get, all etc.) as well as select_related and prefetch_related models (with nested notation).

Mandatory fields cannot be excluded as it will raise ValidationError, to exclude a field it has to be nullable.

Pk column cannot be excluded - it's always auto added even if explicitly excluded.

Parameters:

Name Type Description Default
columns Union[List, str, Set, Dict]

columns to exclude

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
def exclude_fields(self, columns: Union[List, str, Set, Dict]) -> "QuerySet[T]":
    """
    With `exclude_fields()` you can select subset of model columns that will
    be excluded to limit the data load.

    It's the opposite of `fields()` method so check documentation above
    to see what options are available.

    Especially check above how you can pass also nested dictionaries
    and sets as a mask to exclude fields from whole hierarchy.

    Note that `fields()` and `exclude_fields()` works both for main models
    (on normal queries like `get`, `all` etc.)
    as well as `select_related` and `prefetch_related` models
    (with nested notation).

    Mandatory fields cannot be excluded as it will raise `ValidationError`,
    to exclude a field it has to be nullable.

    Pk column cannot be excluded - it's always auto added even
    if explicitly excluded.

    :param columns: columns to exclude
    :type columns: Union[List, str, Set, Dict]
    :return: QuerySet
    :rtype: QuerySet
    """
    return self.fields(columns=columns, _is_exclude=True)

exists() async

Returns a bool value to confirm if there are rows matching the given criteria (applied with filter and exclude if set).

Returns:

Type Description
bool

result of the check

Source code in ormar/queryset/queryset.py
669
670
671
672
673
674
675
676
677
678
679
async def exists(self) -> bool:
    """
    Returns a bool value to confirm if there are rows matching the given criteria
    (applied with `filter` and `exclude` if set).

    :return: result of the check
    :rtype: bool
    """
    expr = self.build_select_expression()
    expr = sqlalchemy.exists(expr).select()
    return await self.database.fetch_val(expr)

fields(columns, _is_exclude=False)

With fields() you can select subset of model columns to limit the data load.

Note that fields() and exclude_fields() works both for main models (on normal queries like get, all etc.) as well as select_related and prefetch_related models (with nested notation).

You can select specified fields by passing a str, List[str], Set[str] or dict with nested definition.

To include related models use notation {related_name}__{column}[__{optional_next} etc.].

fields() can be called several times, building up the columns to select.

If you include related models into select_related() call but you won't specify columns for those models in fields - implies a list of all fields for those nested models.

Mandatory fields cannot be excluded as it will raise ValidationError, to exclude a field it has to be nullable.

Pk column cannot be excluded - it's always auto added even if not explicitly included.

You can also pass fields to include as dictionary or set.

To mark a field as included in a dictionary use it's name as key and ellipsis as value.

To traverse nested models use nested dictionaries.

To include fields at last level instead of nested dictionary a set can be used.

To include whole nested model specify model related field name and ellipsis.

Parameters:

Name Type Description Default
_is_exclude bool

flag if it's exclude or include operation

False
columns Union[List, str, Set, Dict]

columns to include

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
def fields(
    self, columns: Union[List, str, Set, Dict], _is_exclude: bool = False
) -> "QuerySet[T]":
    """
    With `fields()` you can select subset of model columns to limit the data load.

    Note that `fields()` and `exclude_fields()` works both for main models
    (on normal queries like `get`, `all` etc.)
    as well as `select_related` and `prefetch_related`
    models (with nested notation).

    You can select specified fields by passing a `str, List[str], Set[str] or
    dict` with nested definition.

    To include related models use notation
    `{related_name}__{column}[__{optional_next} etc.]`.

    `fields()` can be called several times, building up the columns to select.

    If you include related models into `select_related()` call but you won't specify
    columns for those models in fields - implies a list of all fields for
    those nested models.

    Mandatory fields cannot be excluded as it will raise `ValidationError`,
    to exclude a field it has to be nullable.

    Pk column cannot be excluded - it's always auto added even if
    not explicitly included.

    You can also pass fields to include as dictionary or set.

    To mark a field as included in a dictionary use it's name as key
    and ellipsis as value.

    To traverse nested models use nested dictionaries.

    To include fields at last level instead of nested dictionary a set can be used.

    To include whole nested model specify model related field name and ellipsis.

    :param _is_exclude: flag if it's exclude or include operation
    :type _is_exclude: bool
    :param columns: columns to include
    :type columns: Union[List, str, Set, Dict]
    :return: QuerySet
    :rtype: QuerySet
    """
    excludable = ormar.ExcludableItems.from_excludable(self._excludable)
    excludable.build(
        items=columns,
        model_cls=self.model_cls,  # type: ignore
        is_exclude=_is_exclude,
    )

    return self.rebuild_self(excludable=excludable)

filter(*args, _exclude=False, **kwargs)

Allows you to filter by any Model attribute/field as well as to fetch instances, with a filter across an FK relationship.

You can use special filter suffix to change the filter operands:

  • exact - like album__name__exact='Malibu' (exact match)
  • iexact - like album__name__iexact='malibu' (exact match case insensitive)
  • contains - like album__name__contains='Mal' (sql like)
  • icontains - like album__name__icontains='mal' (sql like case insensitive)
  • in - like album__name__in=['Malibu', 'Barclay'] (sql in)
  • isnull - like album__name__isnull=True (sql is null) (isnotnull album__name__isnull=False (sql is not null))
  • gt - like position__gt=3 (sql >)
  • gte - like position__gte=3 (sql >=)
  • lt - like position__lt=3 (sql <)
  • lte - like position__lte=3 (sql <=)
  • startswith - like album__name__startswith='Mal' (exact start match)
  • istartswith - like album__name__istartswith='mal' (case insensitive)
  • endswith - like album__name__endswith='ibu' (exact end match)
  • iendswith - like album__name__iendswith='IBU' (case insensitive)

Note that you can also use python style filters - check the docs!

Parameters:

Name Type Description Default
_exclude bool

flag if it should be exclude or filter

False
kwargs Any

fields names and proper value types

required

Returns:

Type Description
QuerySet

filtered QuerySet

Source code in ormar/queryset/queryset.py
293
294
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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def filter(  # noqa: A003
    self, *args: Any, _exclude: bool = False, **kwargs: Any
) -> "QuerySet[T]":
    """
    Allows you to filter by any `Model` attribute/field
    as well as to fetch instances, with a filter across an FK relationship.

    You can use special filter suffix to change the filter operands:

    *  exact - like `album__name__exact='Malibu'` (exact match)
    *  iexact - like `album__name__iexact='malibu'` (exact match case insensitive)
    *  contains - like `album__name__contains='Mal'` (sql like)
    *  icontains - like `album__name__icontains='mal'` (sql like case insensitive)
    *  in - like `album__name__in=['Malibu', 'Barclay']` (sql in)
    *  isnull - like `album__name__isnull=True` (sql is null)
       (isnotnull `album__name__isnull=False` (sql is not null))
    *  gt - like `position__gt=3` (sql >)
    *  gte - like `position__gte=3` (sql >=)
    *  lt - like `position__lt=3` (sql <)
    *  lte - like `position__lte=3` (sql <=)
    *  startswith - like `album__name__startswith='Mal'` (exact start match)
    *  istartswith - like `album__name__istartswith='mal'` (case insensitive)
    *  endswith - like `album__name__endswith='ibu'` (exact end match)
    *  iendswith - like `album__name__iendswith='IBU'` (case insensitive)

    Note that you can also use python style filters - check the docs!

    :param _exclude: flag if it should be exclude or filter
    :type _exclude: bool
    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: filtered QuerySet
    :rtype: QuerySet
    """
    filter_groups, select_related = self._resolve_filter_groups(groups=args)
    qryclause = QueryClause(
        model_cls=self.model,
        select_related=select_related,
        filter_clauses=self.filter_clauses,
    )
    filter_clauses, select_related = qryclause.prepare_filter(**kwargs)
    filter_clauses = filter_clauses + filter_groups  # type: ignore
    if _exclude:
        exclude_clauses = filter_clauses
        filter_clauses = self.filter_clauses
    else:
        exclude_clauses = self.exclude_clauses
        filter_clauses = filter_clauses

    return self.rebuild_self(
        filter_clauses=filter_clauses,
        exclude_clauses=exclude_clauses,
        select_related=select_related,
    )

first(*args, **kwargs) async

Gets the first row from the db ordered by primary key column ascending.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
Model

returned model

Raises:

Type Description
NoMatch

if no rows are returned

MultipleMatches

if more than 1 row is returned.

Source code in ormar/queryset/queryset.py
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
async def first(self, *args: Any, **kwargs: Any) -> "T":
    """
    Gets the first row from the db ordered by primary key column ascending.

    :raises NoMatch: if no rows are returned
    :raises MultipleMatches: if more than 1 row is returned.
    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: returned model
    :rtype: Model
    """
    if kwargs or args:
        return await self.filter(*args, **kwargs).first()

    expr = self.build_select_expression(
        limit=1,
        order_bys=(
            [
                OrderAction(
                    order_str=f"{self.model.Meta.pkname}",
                    model_cls=self.model_cls,  # type: ignore
                )
            ]
            if not any([x.is_source_model_order for x in self.order_bys])
            else []
        )
        + self.order_bys,
    )
    rows = await self.database.fetch_all(expr)
    processed_rows = self._process_query_result_rows(rows)
    if self._prefetch_related and processed_rows:
        processed_rows = await self._prefetch_related_models(processed_rows, rows)
    self.check_single_result_rows_count(processed_rows)
    return processed_rows[0]  # type: ignore

get(*args, **kwargs) async

Get's the first row from the db meeting the criteria set by kwargs.

If no criteria set it will return the last row in db sorted by pk.

Passing a criteria is actually calling filter(args, *kwargs) method described below.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
Model

returned model

Raises:

Type Description
NoMatch

if no rows are returned

MultipleMatches

if more than 1 row is returned.

Source code in ormar/queryset/queryset.py
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
async def get(self, *args: Any, **kwargs: Any) -> "T":  # noqa: CCR001
    """
    Get's the first row from the db meeting the criteria set by kwargs.

    If no criteria set it will return the last row in db sorted by pk.

    Passing a criteria is actually calling filter(*args, **kwargs) method described
    below.

    :raises NoMatch: if no rows are returned
    :raises MultipleMatches: if more than 1 row is returned.
    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: returned model
    :rtype: Model
    """
    if kwargs or args:
        return await self.filter(*args, **kwargs).get()

    if not self.filter_clauses:
        expr = self.build_select_expression(
            limit=1,
            order_bys=(
                [
                    OrderAction(
                        order_str=f"-{self.model.Meta.pkname}",
                        model_cls=self.model_cls,  # type: ignore
                    )
                ]
                if not any([x.is_source_model_order for x in self.order_bys])
                else []
            )
            + self.order_bys,
        )
    else:
        expr = self.build_select_expression()

    rows = await self.database.fetch_all(expr)
    processed_rows = self._process_query_result_rows(rows)
    if self._prefetch_related and processed_rows:
        processed_rows = await self._prefetch_related_models(processed_rows, rows)
    self.check_single_result_rows_count(processed_rows)
    return processed_rows[0]  # type: ignore

get_or_create(_defaults=None, *args, **kwargs) async

Combination of create and get methods.

Tries to get a row meeting the criteria for kwargs and if NoMatch exception is raised it creates a new one with given kwargs and _defaults.

Passing a criteria is actually calling filter(args, *kwargs) method described below.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required
_defaults Optional[Dict[str, Any]]

default values for creating object

None

Returns:

Type Description
Tuple("T", bool)

model instance and a boolean

Source code in ormar/queryset/queryset.py
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
async def get_or_create(
    self,
    _defaults: Optional[Dict[str, Any]] = None,
    *args: Any,
    **kwargs: Any,
) -> Tuple["T", bool]:
    """
    Combination of create and get methods.

    Tries to get a row meeting the criteria for kwargs
    and if `NoMatch` exception is raised
    it creates a new one with given kwargs and _defaults.

    Passing a criteria is actually calling filter(*args, **kwargs) method described
    below.

    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :param _defaults: default values for creating object
    :type _defaults: Optional[Dict[str, Any]]
    :return: model instance and a boolean
    :rtype: Tuple("T", bool)
    """
    try:
        return await self.get(*args, **kwargs), False
    except NoMatch:
        _defaults = _defaults or {}
        return await self.create(**{**kwargs, **_defaults}), True

get_or_none(*args, **kwargs) async

Get's the first row from the db meeting the criteria set by kwargs.

If no criteria set it will return the last row in db sorted by pk.

Passing a criteria is actually calling filter(args, *kwargs) method described below.

If not match is found None will be returned.

Parameters:

Name Type Description Default
kwargs Any

fields names and proper value types

required

Returns:

Type Description
Model

returned model

Source code in ormar/queryset/queryset.py
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
async def get_or_none(self, *args: Any, **kwargs: Any) -> Optional["T"]:
    """
    Get's the first row from the db meeting the criteria set by kwargs.

    If no criteria set it will return the last row in db sorted by pk.

    Passing a criteria is actually calling filter(*args, **kwargs) method described
    below.

    If not match is found None will be returned.

    :param kwargs: fields names and proper value types
    :type kwargs: Any
    :return: returned model
    :rtype: Model
    """
    try:
        return await self.get(*args, **kwargs)
    except ormar.NoMatch:
        return None

limit(limit_count, limit_raw_sql=None)

You can limit the results to desired number of parent models.

To limit the actual number of database query rows instead of number of main models use the limit_raw_sql parameter flag, and set it to True.

Parameters:

Name Type Description Default
limit_raw_sql bool

flag if raw sql should be limited

None
limit_count int

number of models to limit

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
def limit(self, limit_count: int, limit_raw_sql: bool = None) -> "QuerySet[T]":
    """
    You can limit the results to desired number of parent models.

    To limit the actual number of database query rows instead of number of main
    models use the `limit_raw_sql` parameter flag, and set it to `True`.

    :param limit_raw_sql: flag if raw sql should be limited
    :type limit_raw_sql: bool
    :param limit_count: number of models to limit
    :type limit_count: int
    :return: QuerySet
    :rtype: QuerySet
    """
    limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql
    return self.rebuild_self(limit_count=limit_count, limit_raw_sql=limit_raw_sql)

max(columns) async

Returns max value of columns for rows matching the given criteria (applied with filter and exclude if set before).

Returns:

Type Description
Any

max value of column(s)

Source code in ormar/queryset/queryset.py
722
723
724
725
726
727
728
729
730
731
732
async def max(self, columns: Union[str, List[str]]) -> Any:  # noqa: A003
    """
    Returns max value of columns for rows matching the given criteria
    (applied with `filter` and `exclude` if set before).

    :return: max value of column(s)
    :rtype: Any
    """
    if not isinstance(columns, list):
        columns = [columns]
    return await self._query_aggr_function(func_name="max", columns=columns)

min(columns) async

Returns min value of columns for rows matching the given criteria (applied with filter and exclude if set before).

Returns:

Type Description
Any

min value of column(s)

Source code in ormar/queryset/queryset.py
734
735
736
737
738
739
740
741
742
743
744
async def min(self, columns: Union[str, List[str]]) -> Any:  # noqa: A003
    """
    Returns min value of columns for rows matching the given criteria
    (applied with `filter` and `exclude` if set before).

    :return: min value of column(s)
    :rtype: Any
    """
    if not isinstance(columns, list):
        columns = [columns]
    return await self._query_aggr_function(func_name="min", columns=columns)

model() property

Shortcut to model class set on QuerySet.

Returns:

Type Description
Type[Model]

model class

Source code in ormar/queryset/queryset.py
 96
 97
 98
 99
100
101
102
103
104
105
106
@property
def model(self) -> Type["T"]:
    """
    Shortcut to model class set on QuerySet.

    :return: model class
    :rtype: Type[Model]
    """
    if not self.model_cls:  # pragma nocover
        raise ValueError("Model class of QuerySet is not initialized")
    return self.model_cls

model_meta() property

Shortcut to model class Meta set on QuerySet model.

Returns:

Type Description
model Meta class

Meta class of the model

Source code in ormar/queryset/queryset.py
84
85
86
87
88
89
90
91
92
93
94
@property
def model_meta(self) -> "ModelMeta":
    """
    Shortcut to model class Meta set on QuerySet model.

    :return: Meta class of the model
    :rtype: model Meta class
    """
    if not self.model_cls:  # pragma nocover
        raise ValueError("Model class of QuerySet is not initialized")
    return self.model_cls.Meta

offset(offset, limit_raw_sql=None)

You can also offset the results by desired number of main models.

To offset the actual number of database query rows instead of number of main models use the limit_raw_sql parameter flag, and set it to True.

Parameters:

Name Type Description Default
limit_raw_sql bool

flag if raw sql should be offset

None
offset int

numbers of models to offset

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
def offset(self, offset: int, limit_raw_sql: bool = None) -> "QuerySet[T]":
    """
    You can also offset the results by desired number of main models.

    To offset the actual number of database query rows instead of number of main
    models use the `limit_raw_sql` parameter flag, and set it to `True`.

    :param limit_raw_sql: flag if raw sql should be offset
    :type limit_raw_sql: bool
    :param offset: numbers of models to offset
    :type offset: int
    :return: QuerySet
    :rtype: QuerySet
    """
    limit_raw_sql = self.limit_sql_raw if limit_raw_sql is None else limit_raw_sql
    return self.rebuild_self(offset=offset, limit_raw_sql=limit_raw_sql)

order_by(columns)

With order_by() you can order the results from database based on your choice of fields.

You can provide a string with field name or list of strings with fields names.

Ordering in sql will be applied in order of names you provide in order_by.

By default if you do not provide ordering ormar explicitly orders by all primary keys

If you are sorting by nested models that causes that the result rows are unsorted by the main model ormar will combine those children rows into one main model.

The main model will never duplicate in the result

To order by main model field just provide a field name

To sort on nested models separate field names with dunder '__'.

You can sort this way across all relation types -> ForeignKey, reverse virtual FK and ManyToMany fields.

To sort in descending order provide a hyphen in front of the field name

Parameters:

Name Type Description Default
columns Union[List, str, OrderAction]

columns by which models should be sorted

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
def order_by(self, columns: Union[List, str, OrderAction]) -> "QuerySet[T]":
    """
    With `order_by()` you can order the results from database based on your
    choice of fields.

    You can provide a string with field name or list of strings with fields names.

    Ordering in sql will be applied in order of names you provide in order_by.

    By default if you do not provide ordering `ormar` explicitly orders by
    all primary keys

    If you are sorting by nested models that causes that the result rows are
    unsorted by the main model `ormar` will combine those children rows into
    one main model.

    The main model will never duplicate in the result

    To order by main model field just provide a field name

    To sort on nested models separate field names with dunder '__'.

    You can sort this way across all relation types -> `ForeignKey`,
    reverse virtual FK and `ManyToMany` fields.

    To sort in descending order provide a hyphen in front of the field name

    :param columns: columns by which models should be sorted
    :type columns: Union[List, str]
    :return: QuerySet
    :rtype: QuerySet
    """
    if not isinstance(columns, list):
        columns = [columns]

    orders_by = [
        OrderAction(order_str=x, model_cls=self.model_cls)  # type: ignore
        if not isinstance(x, OrderAction)
        else x
        for x in columns
    ]

    order_bys = self.order_bys + [x for x in orders_by if x not in self.order_bys]
    return self.rebuild_self(order_bys=order_bys)

paginate(page, page_size=20)

You can paginate the result which is a combination of offset and limit clauses. Limit is set to page size and offset is set to (page-1) * page_size.

Parameters:

Name Type Description Default
page_size int

numbers of items per page

20
page int

page number

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
def paginate(self, page: int, page_size: int = 20) -> "QuerySet[T]":
    """
    You can paginate the result which is a combination of offset and limit clauses.
    Limit is set to page size and offset is set to (page-1) * page_size.

    :param page_size: numbers of items per page
    :type page_size: int
    :param page: page number
    :type page: int
    :return: QuerySet
    :rtype: QuerySet
    """
    if page < 1 or page_size < 1:
        raise QueryDefinitionError("Page size and page have to be greater than 0.")

    limit_count = page_size
    query_offset = (page - 1) * page_size
    return self.rebuild_self(limit_count=limit_count, offset=query_offset)

Allows to prefetch related models during query - but opposite to select_related each subsequent model is fetched in a separate database query.

With prefetch_related always one query per Model is run against the database, meaning that you will have multiple queries executed one after another.

To fetch related model use ForeignKey names.

To chain related Models relation use double underscores between names.

Parameters:

Name Type Description Default
related Union[List, str, FieldAccessor]

list of relation field names, can be linked by '__' to nest

required

Returns:

Type Description
QuerySet

QuerySet

Source code in ormar/queryset/queryset.py
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
def prefetch_related(
    self, related: Union[List, str, FieldAccessor]
) -> "QuerySet[T]":
    """
    Allows to prefetch related models during query - but opposite to
    `select_related` each subsequent model is fetched in a separate database query.

    **With `prefetch_related` always one query per Model is run against the
    database**, meaning that you will have multiple queries executed one
    after another.

    To fetch related model use `ForeignKey` names.

    To chain related `Models` relation use double underscores between names.

    :param related: list of relation field names, can be linked by '__' to nest
    :type related: Union[List, str]
    :return: QuerySet
    :rtype: QuerySet
    """
    if not isinstance(related, list):
        related = [related]
    related = [
        rel._access_chain if isinstance(rel, FieldAccessor) else rel
        for rel in related
    ]

    related = list(set(list(self._prefetch_related) + related))
    return self.rebuild_self(prefetch_related=related)

rebuild_self(filter_clauses=None, exclude_clauses=None, select_related=None, limit_count=None, offset=None, excludable=None, order_bys=None, prefetch_related=None, limit_raw_sql=None, proxy_source_model=None)

Method that returns new instance of queryset based on passed params, all not passed params are taken from current values.

Source code in ormar/queryset/queryset.py
108
109
110
111
112
113
114
115
116
117
118
119
120
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
def rebuild_self(  # noqa: CFQ002
    self,
    filter_clauses: List = None,
    exclude_clauses: List = None,
    select_related: List = None,
    limit_count: int = None,
    offset: int = None,
    excludable: "ExcludableItems" = None,
    order_bys: List = None,
    prefetch_related: List = None,
    limit_raw_sql: bool = None,
    proxy_source_model: Optional[Type["Model"]] = None,
) -> "QuerySet":
    """
    Method that returns new instance of queryset based on passed params,
    all not passed params are taken from current values.
    """
    overwrites = {
        "select_related": "_select_related",
        "offset": "query_offset",
        "excludable": "_excludable",
        "prefetch_related": "_prefetch_related",
        "limit_raw_sql": "limit_sql_raw",
    }
    passed_args = locals()

    def replace_if_none(arg_name: str) -> Any:
        if passed_args.get(arg_name) is None:
            return getattr(self, overwrites.get(arg_name, arg_name))
        return passed_args.get(arg_name)

    return self.__class__(
        model_cls=self.model_cls,