Skip to content

Models

Defining models

By defining an ormar Model you get corresponding Pydantic model as well as Sqlalchemy table for free. They are being managed in the background and you do not have to create them on your own.

Model Class

To build an ormar model you simply need to inherit a ormar.Model class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

Defining Fields

Next assign one or more of the Fields as a class level variables.

Each table has to have a primary key column, which you specify by setting primary_key=True on selected field.

Only one primary key column is allowed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

Warning

Not assigning primary_key column or assigning more than one column per Model will raise ModelDefinitionError exception.

By default if you assign primary key to Integer field, the autoincrement option is set to true.

You can disable by passing autoincremant=False.

1
id: ormar.Integer(primary_key=True, autoincrement=False)

Names of the fields will be used for both the underlying pydantic model and sqlalchemy table.

Dependencies

Since ormar depends on databases and sqlalchemy-core for database connection and table creation you need to assign each Model with two special parameters.

Databases

One is Database instance created with your database url in sqlalchemy connection string format.

Created instance needs to be passed to every Model with Meta class database parameter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

Tip

You need to create the Database instance only once and use it for all models. You can create several ones if you want to use multiple databases.

Sqlalchemy

Second dependency is sqlalchemy MetaData instance.

Created instance needs to be passed to every Model with Meta class metadata parameter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

Tip

You need to create the MetaData instance only once and use it for all models. You can create several ones if you want to use multiple databases.

Table Names

By default table name is created from Model class name as lowercase name plus 's'.

You can overwrite this parameter by providing Meta class tablename argument.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        # if you omit this parameter it will be created automatically
        # as class.__name__.lower()+'s' -> "courses" in this example
        tablename = "my_courses"
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

Constraints

On a model level you can also set model-wise constraints on sql columns.

Right now only UniqueColumns constraint is present.

Tip

To read more about columns constraints like primary_key, unique, ForeignKey etc. visit fields.

You can set this parameter by providing Meta class constraints argument.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata
        # define your constraints in Meta class of the model
        # it's a list that can contain multiple constraints
        # hera a combination of name and column will have to be unique in db
        constraints = [ormar.UniqueColumns('name', 'completed')]

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=100)
    completed = ormar.Boolean(default=False)

Initialization

There are two ways to create and persist the Model instance in the database.

Tip

Use ipython to try this from the console, since it supports await.

If you plan to modify the instance in the later execution of your program you can initiate your Model as a normal class and later await a save() call.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=100)
    completed = ormar.Boolean(default=False)


course = Course(name="Painting for dummies", completed=False)
await course.save()

await Course.objects.create(name="Painting for dummies", completed=False)

If you want to initiate your Model and at the same time save in in the database use a QuerySet's method create().

For creating multiple objects at once a bulk_create() QuerySet's method is available.

Each model has a QuerySet initialised as objects parameter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=100)
    completed = ormar.Boolean(default=False)


course = Course(name="Painting for dummies", completed=False)
await course.save()

await Course.objects.create(name="Painting for dummies", completed=False)

Info

To read more about QuerySets (including bulk operations) and available methods visit queries

Model methods

load

By default when you query a table without prefetching related models, the ormar will still construct your related models, but populate them only with the pk value.

1
2
3
4
5
6
7
track = await Track.objects.get(name='The Bird')
track.album.pk # will return malibu album pk (1)
track.album.name # will return None

# you need to actually load the data first
await track.album.load()
track.album.name # will return 'Malibu'

save

delete

update

Internals

Apart from special parameters defined in the Model during definition (tablename, metadata etc.) the Model provides you with useful internals.

Pydantic Model

All Model classes inherit from pydantic.BaseModel so you can access all normal attributes of pydantic models.

For example to list pydantic model fields you can:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)


print(Course.__fields__)
"""
Will produce:
{'id':        ModelField(name='id', 
                         type=Optional[int], 
                         required=False, 
                         default=None),
 'name':      ModelField(name='name', 
                         type=Optional[str], 
                         required=False, 
                         default=None),
'completed':  ModelField(name='completed', 
                         type=bool, 
                         required=False, 
                         default=False)}
"""

Tip

Note how the primary key id field is optional as Integer primary key by default has autoincrement set to True.

Info

For more options visit official pydantic documentation.

Sqlalchemy Table

To access auto created sqlalchemy table you can use Model.Meta.table parameter

For example to list table columns you can:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)


print(Course.Meta.table.columns)
"""
Will produce:
['courses.id', 'courses.name', 'courses.completed']
"""

Tip

You can access table primary key name by Course.Meta.pkname

Info

For more options visit official sqlalchemy-metadata documentation.

Fields Definition

To access ormar Fields you can use Model.Meta.model_fields parameter

For example to list table model fields you can:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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
import databases
import sqlalchemy

import ormar

database = databases.Database("sqlite:///db.sqlite")
metadata = sqlalchemy.MetaData()


class Course(ormar.Model):
    class Meta:
        database = database
        metadata = metadata

    id: ormar.Integer(primary_key=True)
    name: ormar.String(max_length=100)
    completed: ormar.Boolean(default=False)

print({x:v.__dict__ for x,v in Course.Meta.model_fields.items()})
"""
Will produce:
{'completed': mappingproxy({'autoincrement': False,
                            'choices': set(),
                            'column_type': Boolean(),
                            'default': False,
                            'index': False,
                            'name': 'completed',
                            'nullable': True,
                            'primary_key': False,
                            'pydantic_only': False,
                            'server_default': None,
                            'unique': False}),
 'id': mappingproxy({'autoincrement': True,
                     'choices': set(),
                     'column_type': Integer(),
                     'default': None,
                     'ge': None,
                     'index': False,
                     'le': None,
                     'maximum': None,
                     'minimum': None,
                     'multiple_of': None,
                     'name': 'id',
                     'nullable': False,
                     'primary_key': True,
                     'pydantic_only': False,
                     'server_default': None,
                     'unique': False}),
 'name': mappingproxy({'allow_blank': False,
                       'autoincrement': False,
                       'choices': set(),
                       'column_type': String(length=100),
                       'curtail_length': None,
                       'default': None,
                       'index': False,
                       'max_length': 100,
                       'min_length': None,
                       'name': 'name',
                       'nullable': False,
                       'primary_key': False,
                       'pydantic_only': False,
                       'regex': None,
                       'server_default': None,
                       'strip_whitespace': False,
                       'unique': False})}
"""

Info

Note that fields stored on a model are classes not instances.

So if you print just model fields you will get:

{'id': <class 'ormar.fields.model_fields.Integer'>,

'name': <class 'ormar.fields.model_fields.String'>,

'completed': <class 'ormar.fields.model_fields.Boolean'>}