A Django REST framework API adapter for the JSON:API spec.
—
JSON:API compliant pagination classes that provide proper meta information and navigation links, supporting both page number and limit/offset pagination styles according to JSON:API specification.
Page number based pagination with JSON:API compliant query parameters and response format.
class JsonApiPageNumberPagination(PageNumberPagination):
"""
JSON:API compliant page number pagination.
Uses JSON:API recommended query parameters:
- page[number]: Page number (1-based)
- page[size]: Items per page
Returns JSON:API compliant pagination metadata and links.
"""
page_query_param = "page[number]" # Query parameter for page number
page_size_query_param = "page[size]" # Query parameter for page size
max_page_size = 100 # Maximum allowed page size
def build_link(self, index):
"""
Build pagination link for given page index.
Args:
index: Page number (1-based) or None
Returns:
str or None: Full URL for the page
"""
def get_paginated_response(self, data):
"""
Generate JSON:API compliant paginated response.
Args:
data: Serialized page data
Returns:
Response: JSON:API response with data, meta, and links
"""Usage example:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
'PAGE_SIZE': 20
}
# Or in view class:
from rest_framework_json_api.pagination import JsonApiPageNumberPagination
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
pagination_class = JsonApiPageNumberPagination
# Request: GET /articles?page[number]=2&page[size]=10
# Response:
{
"data": [...],
"meta": {
"pagination": {
"page": 2,
"pages": 15,
"count": 150
}
},
"links": {
"first": "/articles?page[number]=1",
"prev": "/articles?page[number]=1",
"next": "/articles?page[number]=3",
"last": "/articles?page[number]=15"
}
}Limit/offset based pagination with JSON:API compliant query parameters.
class JsonApiLimitOffsetPagination(LimitOffsetPagination):
"""
JSON:API compliant limit/offset pagination.
Uses JSON:API recommended query parameters:
- page[limit]: Number of items to return
- page[offset]: Number of items to skip
Returns JSON:API compliant pagination metadata and links.
"""
limit_query_param = "page[limit]" # Query parameter for limit
offset_query_param = "page[offset]" # Query parameter for offset
max_limit = 100 # Maximum allowed limit
def get_last_link(self):
"""
Generate link to last page.
Returns:
str or None: URL for last page
"""
def get_first_link(self):
"""
Generate link to first page.
Returns:
str or None: URL for first page
"""
def get_paginated_response(self, data):
"""
Generate JSON:API compliant paginated response.
Args:
data: Serialized page data
Returns:
Response: JSON:API response with data, meta, and links
"""Usage example:
from rest_framework_json_api.pagination import JsonApiLimitOffsetPagination
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
pagination_class = JsonApiLimitOffsetPagination
# Request: GET /articles?page[limit]=10&page[offset]=20
# Response:
{
"data": [...],
"meta": {
"pagination": {
"count": 150,
"limit": 10,
"offset": 20
}
},
"links": {
"first": "/articles",
"prev": "/articles?page[limit]=10&page[offset]=10",
"next": "/articles?page[limit]=10&page[offset]=30",
"last": "/articles?page[limit]=10&page[offset]=140"
}
}Both pagination classes generate JSON:API compliant responses with the following structure:
{
"data": [
# Array of resource objects
],
"meta": {
"pagination": {
"page": 2, # Current page number (1-based)
"pages": 15, # Total number of pages
"count": 150 # Total number of items
}
},
"links": {
"first": "/articles?page[number]=1", # First page
"prev": "/articles?page[number]=1", # Previous page (null if first)
"next": "/articles?page[number]=3", # Next page (null if last)
"last": "/articles?page[number]=15" # Last page
}
}{
"data": [
# Array of resource objects
],
"meta": {
"pagination": {
"count": 150, # Total number of items
"limit": 10, # Items per page
"offset": 20 # Number of items skipped
}
},
"links": {
"first": "/articles", # First page
"prev": "/articles?page[limit]=10&page[offset]=10", # Previous page
"next": "/articles?page[limit]=10&page[offset]=30", # Next page
"last": "/articles?page[limit]=10&page[offset]=140" # Last page
}
}# Basic pagination
GET /articles?page[number]=3
# With custom page size
GET /articles?page[number]=3&page[size]=25
# Combined with other parameters
GET /articles?page[number]=2&page[size]=10&include=author&sort=title# Basic limit/offset
GET /articles?page[limit]=20&page[offset]=40
# Limit only (offset defaults to 0)
GET /articles?page[limit]=15
# Combined with other parameters
GET /articles?page[limit]=10&page[offset]=20&filter[published]=true# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
'PAGE_SIZE': 20
}from rest_framework_json_api.pagination import JsonApiPageNumberPagination
class CustomPagination(JsonApiPageNumberPagination):
page_size = 25
max_page_size = 50
def get_paginated_response(self, data):
response = super().get_paginated_response(data)
# Add custom meta information
response.data['meta']['custom'] = 'value'
return responseclass ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
pagination_class = JsonApiLimitOffsetPagination
def get_paginated_response(self, data):
response = super().get_paginated_response(data)
# Add view-specific meta information
response.data['meta']['view'] = 'articles'
return responseWhen no results are found:
{
"data": [],
"meta": {
"pagination": {
"page": 1,
"pages": 0,
"count": 0
}
},
"links": {
"first": null,
"prev": null,
"next": null,
"last": null
}
}Invalid pagination parameters return appropriate errors:
# Invalid page number
GET /articles?page[number]=invalid
# Response:
{
"errors": [{
"detail": "Invalid page number.",
"status": "400"
}]
}
# Page size too large
GET /articles?page[size]=500
# Response:
{
"errors": [{
"detail": "Page size too large. Maximum is 100.",
"status": "400"
}]
}Links preserve existing query parameters:
# Request: GET /articles?include=author&sort=title&page[number]=2
# Links include the other parameters:
{
"links": {
"first": "/articles?include=author&sort=title&page[number]=1",
"next": "/articles?include=author&sort=title&page[number]=3",
# ...
}
}from rest_framework_json_api.pagination import (
JsonApiPageNumberPagination,
JsonApiLimitOffsetPagination
)
# Base classes from Django REST framework
from rest_framework.pagination import (
PageNumberPagination,
LimitOffsetPagination
)Install with Tessl CLI
npx tessl i tessl/pypi-djangorestframework-jsonapi