Skip to content

Commit 1eecf86

Browse files
committed
Adds docs for CursorPaginator
1 parent ad814d6 commit 1eecf86

File tree

1 file changed

+76
-19
lines changed

1 file changed

+76
-19
lines changed

docs/docs/guides/response/pagination.md

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
**Django Ninja** comes with a pagination support. This allows you to split large result sets into individual pages.
44

5-
65
To apply pagination to a function - just apply `paginate` decorator:
76

87
```python hl_lines="1 4"
@@ -14,7 +13,6 @@ def list_users(request):
1413
return User.objects.all()
1514
```
1615

17-
1816
That's it!
1917

2018
Now you can query users with `limit` and `offset` GET parameters
@@ -25,7 +23,6 @@ Now you can query users with `limit` and `offset` GET parameters
2523

2624
by default limit is set to `100` (you can change it in your settings.py using `NINJA_PAGINATION_PER_PAGE`)
2725

28-
2926
## Built in Pagination Classes
3027

3128
### LimitOffsetPagination (default)
@@ -42,17 +39,18 @@ def list_users(request):
4239
```
4340

4441
Example query:
42+
4543
```
4644
/api/users?limit=10&offset=0
4745
```
4846

4947
this class has two input parameters:
5048

51-
- `limit` - defines a number of queryset on the page (default = 100, change in NINJA_PAGINATION_PER_PAGE)
52-
- `offset` - set's the page window offset (default: 0, indexing starts with 0)
53-
49+
- `limit` - defines a number of queryset on the page (default = 100, change in NINJA_PAGINATION_PER_PAGE)
50+
- `offset` - set's the page window offset (default: 0, indexing starts with 0)
5451

5552
### PageNumberPagination
53+
5654
```python hl_lines="1 4"
5755
from ninja.pagination import paginate, PageNumberPagination
5856

@@ -63,11 +61,12 @@ def list_users(request):
6361
```
6462

6563
Example query:
64+
6665
```
6766
/api/users?page=2
6867
```
6968

70-
this class has one parameter `page` and outputs 100 queryset per page by default (can be changed with settings.py)
69+
this class has one parameter `page` and outputs 100 queryset per page by default (can be changed with settings.py)
7170

7271
Page numbering start with 1
7372

@@ -82,12 +81,74 @@ def list_users(...
8281
In addition to the `page` parameter, you can also use the `page_size` parameter to dynamically adjust the number of records displayed per page:
8382

8483
Example query:
84+
8585
```
8686
/api/users?page=2&page_size=20
8787
```
8888

8989
This allows you to temporarily override the page size setting in your request. The request will use the specified `page_size` value if provided. Otherwise, it will use either the value specified in the decorator or the value from `PAGINATION_MAX_PER_PAGE_SIZE` in settings.py if no decorator value is set.
9090

91+
### CursorPagination
92+
93+
Cursor-based pagination provides stable pagination for datasets that may change frequently. Cursor pagination uses base64 encoded tokens to mark positions in the dataset, ensuring consistent results even when items are added or removed.
94+
95+
```python hl_lines="1 4"
96+
from ninja.pagination import paginate, CursorPagination
97+
98+
@api.get('/events', response=List[EventSchema])
99+
@paginate(CursorPagination)
100+
def list_events(request):
101+
return Event.objects.all()
102+
```
103+
104+
Example query:
105+
106+
```
107+
/api/events?cursor=eyJwIjoiMjAyNC0wMS0wMSIsInIiOmZhbHNlLCJvIjowfQ==
108+
```
109+
110+
this class has two input parameters:
111+
112+
- `cursor` - base64 token representing the current position (optional, starts from beginning if not provided)
113+
- `page_size` - number of items per page (optional)
114+
115+
You can specify the `page_size` value to temporarily override in the request:
116+
117+
```
118+
/api/events?cursor=eyJwIjoiMjAyNC0wMS0wMSIsInIiOmZhbHNlLCJvIjowfQ==&page_size=5
119+
```
120+
121+
This class has a few parameters, which determine how the cursor position is ascertained and the parameter encoded:
122+
123+
- `ordering` - tuple of field names to order the queryset. Use `-` prefix for descending order. The first one of which will be used to encode the position. The ordering field should be unique if possible. A string representation of this field will be used to point to the current position of the cursor. Timestamps work well if each item in the collection is created independently. The paginator can handle some non-uniqueness by adding an offset. Defaults to `("-created",)`, change in `NINJA_PAGINATION_DEFAULT_ORDERING`
124+
125+
- `page_size` - default page size for endpoint. Defaults to `100`, change in `NINJA_PAGINATION_PER_PAGE`
126+
- `max_page_size` - maximum allowed page size for endpoint. Defaults to `100`, change in `NINJA_PAGINATION_MAX_PER_PAGE_SIZE`
127+
128+
Finally, there is a `NINJA_PAGINATION_MAX_OFFSET` setting to limit malicious cursor requests. It defaults to `100`.
129+
130+
The class parameters can be set globally via settings as well as per view:
131+
132+
```python hl_lines="2"
133+
@api.get("/events")
134+
@paginate(CursorPagination, ordering=("start_date", "end_date"), page_size=20, max_page_size=100)
135+
def list_events(request):
136+
return Event.objects.all()
137+
```
138+
139+
The response includes navigation links and results:
140+
141+
```json
142+
{
143+
"next": "http://api.example.com/events?cursor=eyJwIjoiMjAyNC0wMS0wMiIsInIiOmZhbHNlLCJvIjowfQ==",
144+
"previous": "http://api.example.com/events?cursor=eyJwIjoiMjAyNC0wMS0wMSIsInIiOnRydWUsIm8iOjB9",
145+
"results": [
146+
{ "id": 1, "title": "Event 1", "start_date": "2024-01-01" },
147+
{ "id": 2, "title": "Event 2", "start_date": "2024-01-02" }
148+
]
149+
}
150+
```
151+
91152
## Accessing paginator parameters in view function
92153

93154
If you need access to `Input` parameters used for pagination in your view function - use `pass_parameter` argument
@@ -102,18 +163,16 @@ def someview(request, **kwargs):
102163
return ...
103164
```
104165

105-
106166
## Creating Custom Pagination Class
107167

108168
To create a custom pagination class you should subclass `ninja.pagination.PaginationBase` and override the `Input` and `Output` schema classes and `paginate_queryset(self, queryset, request, **params)` method:
109169

110-
- The `Input` schema is a Schema class that describes parameters that should be passed to your paginator (f.e. page-number or limit/offset values).
111-
- The `Output` schema describes schema for page output (f.e. count/next-page/items/etc).
112-
- The `paginate_queryset` method is passed the initial queryset and should return an iterable object that contains only the data in the requested page. This method accepts the following arguments:
113-
- `queryset`: a queryset (or iterable) returned by the api function
114-
- `pagination` - the paginator.Input parameters (parsed and validated)
115-
- `**params`: kwargs that will contain all the arguments that decorated function received
116-
170+
- The `Input` schema is a Schema class that describes parameters that should be passed to your paginator (f.e. page-number or limit/offset values).
171+
- The `Output` schema describes schema for page output (f.e. count/next-page/items/etc).
172+
- The `paginate_queryset` method is passed the initial queryset and should return an iterable object that contains only the data in the requested page. This method accepts the following arguments:
173+
- `queryset`: a queryset (or iterable) returned by the api function
174+
- `pagination` - the paginator.Input parameters (parsed and validated)
175+
- `**params`: kwargs that will contain all the arguments that decorated function received
117176

118177
Example:
119178

@@ -126,7 +185,7 @@ class CustomPagination(PaginationBase):
126185
# only `skip` param, defaults to 5 per page
127186
class Input(Schema):
128187
skip: int
129-
188+
130189

131190
class Output(Schema):
132191
items: List[Any] # `items` is a default attribute
@@ -170,12 +229,11 @@ class CustomPagination(PaginationBase):
170229
results: List[Any]
171230
total: int
172231
per_page: int
173-
232+
174233
items_attribute: str = "results"
175234

176235
```
177236

178-
179237
## Apply pagination to multiple operations at once
180238

181239
There is often a case when you need to add pagination to all views that returns querysets or list
@@ -202,7 +260,6 @@ In this example both operations will have pagination enabled
202260

203261
to apply pagination to main `api` instance use `default_router` argument:
204262

205-
206263
```python
207264
api = NinjaAPI(default_router=RouterPaginated())
208265

0 commit comments

Comments
 (0)