Pagination
Default pagination
An interface for limit/offset pagination can be use for basic pagination needs:
@strawberry_django.type(models.Fruit, pagination=True)class Fruit: name: auto
@strawberry.typeclass Query: fruits: list[Fruit] = strawberry_django.field()
Would produce the following schema:
type Fruit { name: String!}
input OffsetPaginationInput { offset: Int! = 0 limit: Int = null}
type Query { fruits(pagination: OffsetPaginationInput): [Fruit!]!}
And can be queried like:
query { fruits(pagination: { offset: 0, limit: 2 }) { name }}
The pagination
argument can be given to the type, which will enforce the pagination
argument every time the field is annotated as a list, but you can also give it directly
to the field for more control, like:
@strawberry_django.type(models.Fruit)class Fruit: name: auto
@strawberry.typeclass Query: fruits: list[Fruit] = strawberry_django.field(pagination=True)
Which will produce the exact same schema.
Default limit for pagination
The default limit for pagination is set to 100
. This can be changed in the
strawberry django settings to increase or decrease that number,
or even set to None
to set it to unlimited.
To configure it on a per field basis, you can define your own OffsetPaginationInput
subclass and modify its default value, like:
@strawberry.inputdef MyOffsetPaginationInput(OffsetPaginationInput): limit: int = 250
# Pass it to the pagination argument when defining the type@strawberry_django.type(models.Fruit, pagination=MyOffsetPaginationInput)class Fruit: ...
@strawberry.typeclass Query: # Or pass it to the pagination argument when defining the field fruits: list[Fruit] = strawberry_django.field(pagination=MyOffsetPaginationInput)
OffsetPaginated Generic
For more complex pagination needs, you can use the OffsetPaginated
generic, which alongside
the pagination
argument, will wrap the results in an object that contains the results
and the pagination information, together with the totalCount
of elements excluding pagination.
from strawberry_django.pagination import OffsetPaginated
@strawberry_django.type(models.Fruit)class Fruit: name: auto
@strawberry.typeclass Query: fruits: OffsetPaginated[Fruit] = strawberry_django.offset_paginated()
Would produce the following schema:
type Fruit { name: String!}
type PaginationInfo { limit: Int = null offset: Int!}
type FruitOffsetPaginated { pageInfo: PaginationInfo! totalCount: Int! results: [Fruit]!}
input OffsetPaginationInput { offset: Int! = 0 limit: Int = null}
type Query { fruits(pagination: OffsetPaginationInput): [FruitOffsetPaginated!]!}
Which can be queried like:
query { fruits(pagination: { offset: 0, limit: 2 }) { totalCount pageInfo { limit offset } results { name } }}
Note
OffsetPaginated follow the same rules for the default pagination limit, and can be configured in the same way as explained above.
Customizing queryset resolver
It is possible to define a custom resolver for the queryset to either provide a custom queryset for it, or even to receive extra arguments alongside the pagination arguments.
Suppose we want to pre-filter a queryset of fruits for only available ones, while also adding ordering to it. This can be achieved with:
@strawberry_django.type(models.Fruit)class Fruit: name: auto price: auto
@strawberry_django.order(models.Fruit)class FruitOrder: name: auto price: auto
@strawberry.typeclass Query: @strawberry_django.offset_paginated(OffsetPaginated[Fruit], order=order) def fruits(self, only_available: bool = True) -> QuerySet[Fruit]: queryset = models.Fruit.objects.all() if only_available: queryset = queryset.filter(available=True)
return queryset
This would produce the following schema:
type Fruit { name: String! price: Decimal!}
type FruitOrder { name: Ordering price: Ordering}
type PaginationInfo { limit: Int! offset: Int!}
type FruitOffsetPaginated { pageInfo: PaginationInfo! totalCount: Int! results: [Fruit]!}
input OffsetPaginationInput { offset: Int! = 0 limit: Int = null}
type Query { fruits( onlyAvailable: Boolean! = true pagination: OffsetPaginationInput order: FruitOrder ): [FruitOffsetPaginated!]!}
Customizing the pagination
Like other generics, OffsetPaginated
can be customized to modify its behavior or to
add extra functionality in it. For example, suppose we want to add the average
price of the fruits in the pagination:
from strawberry_django.pagination import OffsetPaginated
@strawberry_django.type(models.Fruit)class Fruit: name: auto price: auto
@strawberry.typeclass FruitOffsetPaginated(OffsetPaginated[Fruit]): @strawberry_django.field def average_price(self) -> Decimal: if self.queryset is None: return Decimal(0)
return self.queryset.aggregate(Avg("price"))["price__avg"]
@strawberry_django.field def paginated_average_price(self) -> Decimal: paginated_queryset = self.get_paginated_queryset() if paginated_queryset is None: return Decimal(0)
return paginated_queryset.aggregate(Avg("price"))["price__avg"]
@strawberry.typeclass Query: fruits: FruitOffsetPaginated = strawberry_django.offset_paginated()
Would produce the following schema:
type Fruit { name: String!}
type PaginationInfo { limit: Int = null offset: Int!}
type FruitOffsetPaginated { pageInfo: PaginationInfo! totalCount: Int! results: [Fruit]! averagePrice: Decimal! paginatedAveragePrice: Decimal!}
input OffsetPaginationInput { offset: Int! = 0 limit: Int = null}
type Query { fruits(pagination: OffsetPaginationInput): [FruitOffsetPaginated!]!}
The following attributes/methods can be accessed in the OffsetPaginated
class:
-
queryset
: The queryset original queryset with any filters/ordering applied, but not paginated yet -
pagination
: TheOffsetPaginationInput
object, with theoffset
andlimit
for pagination -
get_total_count()
: Returns the total count of elements in the queryset without pagination -
get_paginated_queryset()
: Returns the queryset with pagination applied -
resolve_paginated(queryset, *, info, pagination, **kwargs)
: The classmethod that strawberry-django calls to create an instance of theOffsetPaginated
class/subclass.
Cursor pagination (aka Relay style pagination)
Another option for pagination is to use a relay style cursor pagination . For this, you can leverage the relay integration provided by strawberry to create a relay connection.