Tutorial
Step 6 of 7
Filter, search and sort¶
In this step you let clients narrow down the article list:
Text Only
GET /api/articles?title=django&category=1&search=async&ordering=-views&page=2
Add the filters¶
Declare the query parameters in query_params and add the mixins that apply
them. Each parameter is a (type, default) pair.
blog/api.py
from ninja_aio.schemas import RelationFilterSchema
from ninja_aio.views.mixins import (
IcontainsFilterViewSetMixin,
PermissionViewSetMixin,
RelationFilterViewSetMixin,
SearchViewSetMixin,
)
@api.viewset(model=Article)
class ArticleViewSet(
IcontainsFilterViewSetMixin,
RelationFilterViewSetMixin,
SearchViewSetMixin,
PermissionViewSetMixin,
APIViewSet,
):
# auth and permission methods as before
query_params = {"title": (str, None)}
relations_filters = [
RelationFilterSchema(
query_param="category",
query_filter="category__id",
filter_type=(int, None),
),
]
search_fields = ["title", "body", "category__name"]
ordering_fields = ["created_at", "title", "views"]
default_ordering = "-created_at"
Put the mixins before APIViewSet. They work the same in sync and async
viewsets.
| Parameter | Example | Result |
|---|---|---|
title |
?title=django |
Titles that contain "django", ignoring case |
category |
?category=1 |
Articles in category 1 |
search |
?search=async |
"async" in the title, body or category name |
ordering |
?ordering=-views,title |
Most viewed first, then by title |
Parameters you don't send are ignored. ordering only accepts fields listed in
ordering_fields. Without it, the list uses default_ordering.
Other filter mixins¶
| Mixin | Filters | Example |
|---|---|---|
IcontainsFilterViewSetMixin |
Text that contains the value | ?title=django |
BooleanFilterViewSetMixin |
Exact True/False |
?is_published=true |
NumericFilterViewSetMixin |
Exact numbers | ?views=100 |
GreaterEqualDateFilterViewSetMixin |
Dates from this value on | ?created_at=2026-01-01 |
LessEqualDateFilterViewSetMixin |
Dates up to this value | ?created_at=2026-12-31 |
RelationFilterViewSetMixin |
A field on a related model | ?category=1 |
MatchCaseFilterViewSetMixin |
Different filters for true and false |
?popular=true |
Each mixin handles the parameters of its type, so you can combine them.
Paginate¶
The list is split in pages of 100 items. Clients choose the page and its size:
Text Only
GET /api/articles?page=2&page_size=20
Change the default size in your settings:
project/settings.py
NINJA_PAGINATION_PER_PAGE = 20