Skip to content

query set proxy

Returns a list of related models when directly accessing the related ManyToMany field and ReverseForeignKey.

But it also exposes a subset of the QuerySet API, so you can filter, create, select related models, and so on directly from the parent model.

!!!Note that by default, the exposed QuerySet has been filtered to return only models related to the parent model.

1
So if you issue `post.categories.all()` you will get all categories related to that post, not all in table.

!!!note Note that when accessing QuerySet API methods through QuerysetProxy, you do not need to use object properties like normal queries.

1
2
3
So note that it's `post.categories.all()` and **not** `post.categories.objects.all()`.

To learn more about available QuerySet methods visit [queries][queries]

!!!Warning Querying related models from ManyToMany clears the list of related models loaded on the parent model:

1
2
3
4
5
6
7
8
9
Example: `post.categories.first()` will set post.categories to list of 1 related model -> the one returned by first()

Example 2: if post has 4 categories so `len(post.categories) == 4` calling `post.categories.limit(2).all()`
-> will load only 2 children and now `assert len(post.categories) == 2`

This happens for all QuerysetProxy methods returning data: `get`, `all` and `first` and in `get_or_create` if model already exists.

Note that value returned by `create` or created in `get_or_create` and `update_or_create`
if model does not exist will be added to relation list (not clearing it).

Read data from database

get

get(**kwargs): -> Model

To get only one of the related models filtered by name, you can use get(**kwargs) method.

1
2
3
4
5
6
7
8
9
# grab one category
assert news == await post.categories.get(name="News")

# note that method returns the category so you can grab this value
# but it also modifies list of related models in place
# so regardless of what was previously loaded on parent model
# now it has only one value -> just loaded with get() call
assert len(post.categories) == 1
assert post.categories[0] == news

Tip

acquiring or creating

get_or_create(_defaults: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[Model, bool]

Attempts to get rows that meet the condition, and if a NoMatch exception is thrown, a new row is created with the given kwargs and_defaults.

!!!tip Read more in the query document get_or_create

all

all(**kwargs) -> List[Optional["Model"]]

To get a list of related models, use the all() method.

Note that you can filter the query set, select related, exclude fields, and so on just like a normal query.

1
2
3
4
5
6
7
# with all Queryset methods - filtering, selecting columns, counting etc.
await news.posts.filter(title__contains="M2M").all()
await Category.objects.filter(posts__author=guido).get()

# columns models of many to many relation can be prefetched
news_posts = await news.posts.select_related("author").all()
assert news_posts[0].author == guido

Tip

iteration

iterate(**kwargs) -> AsyncGenerator["Model"]

To iterate over related models, use the iterate() method.

Note that you can filter the query set, select related, exclude fields, and so on just like a normal query.

1
2
3
# iterate on categories of this post with an async generator
async for category in post.categories.iterate():
    print(category.name)

Tip

Insert/update data to database

create

Create (**kwargs): -> Model

Create dependent models directly from parent models.

Link tables and relationship IDs in the database are automatically populated.

1
2
3
4
# Creating columns object from instance:
await post.categories.create(name="Tips")
assert len(await post.categories.all()) == 2
# newly created instance already have relation persisted in the database

Tip

For many-to-many relationships, if you declare additional fields on an explicitly provided pass-through model, there is an additional capability of passing parameters that will be used to create the pass-through model.

Given such a sample:

 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
import databases
import ormar
import sqlalchemy

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)


class Category(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="categories")

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=40)


class PostCategory(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="posts_x_categories")

    id: int = ormar.Integer(primary_key=True)
    sort_order: int = ormar.Integer(nullable=True)
    param_name: str = ormar.String(default="Name", max_length=200)


class Post(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    categories = ormar.ManyToMany(Category, through=PostCategory)

You can populate fields from the model in the create() call in the following ways:

1
2
3
4
5
6
7
post = await Post(title="Test post").save()
await post.categories.create(
    name="Test category1",
    # in arguments pass a dictionary with name of the through field and keys
    # corresponding to through model fields
    postcategory={"sort_order": 1, "param_name": "volume"},
)

acquiring or creating

get_or_create(_defaults: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[Model, bool]

Attempts to get rows that meet the condition, and if a NoMatch exception is thrown, a new row is created with the given kwargs.

!!!tip Read more in the query document get_or_create

update or create

update_or_create(**kwargs) -> Model

Update the model or create a new model if there are no matches in the database.

!!!tip Read more in the query document update_or_create

update

update(**kwargs, each:bool = False) -> int

Updates the correlation model with the supplied keyword parameters, returning the updated number of rows.

Tip

Note that parameters with field names and field dictionaries are also accepted for many-to-many relational updates.

 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
import databases
import ormar
import sqlalchemy

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)


class Category(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="categories")

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=40)


class PostCategory(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="posts_x_categories")

    id: int = ormar.Integer(primary_key=True)
    sort_order: int = ormar.Integer(nullable=True)
    param_name: str = ormar.String(default="Name", max_length=200)


class Post(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    categories = ormar.ManyToMany(Category, through=PostCategory)

In the example above, you can update postcategory properties in the following call:

1
2
3
await post.categories.filter(name="Test category3").update(
            postcategory={"sort_order": 4}
        )

filtering and sorting

screen

filter(*args, **kwargs) -> QuerySet

Allows you to filter by any model attribute/field and get instances using filters across FK relationships.

Tip

exclude

exclude(*args, **kwargs) -> QuerySet

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

Tip

Order Basis

order_by(columns:Union[List, str]) -> QuerySet

Using order_by(), you can sort the results in the database based on the fields you select.

!!!tip Read more in query document order_by

Join and subquery

select the relevant

select_related(related: Union[List, str]) -> QuerySet

Allows prefetching related models during the same query.

When using select_lated, only one query is always run against the database, which means that a (sometimes complex) join is generated and later nested models are processed in python.

!!!tip Read more about select_lated in the query documentation

prefetch correlation

prefetch_related(related: Union[List, str]) -> QuerySet

Allow prefetching of related models during query-but as opposed to select_lated, each subsequent model is retrieved in a separate database query.

With prefetch_lated, each model runs a query against the database, which means you execute multiple queries one after the other.

!!!tip Read more in query document prefetch_lated

Pages and rows

paging

paginate(page: int, page_size: int = 20) -> QuerySet

Combines offset and restriction methods based on page number and size.

Tip

impose restrictions on

limit(limit_count: int) -> QuerySet

You can limit the results to the number of parent models you want.

Tip

counteract

offset(offset: int) -> QuerySet

You can offset the results by the number of master models required.

Tip

Select a subset of columns

territory

fields(columns: Union[List, str, set, dict]) -> QuerySet

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

Tip

exclusion field

exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet

With except_fields(), you can select a subset of model columns to exclude to limit data loading.

!!!tip Learn more in the query documentation except_fields

aggregate function

count

count(distinct: bool = True) -> int

Returns the number of rows matching a given condition (i.e. filters and exclusions applied)

Tip

exist

Existence () -> Boolean

Returns a Boolean value to confirm that there are rows that match the given criteria (applied with filters and exclusions)

Tip