Skip to content

Commit

Permalink
Pagination support
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalik committed Aug 14, 2021
1 parent 9379987 commit c8e07b1
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 14 deletions.
51 changes: 46 additions & 5 deletions docs/docs/tutorial/pagination.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Pagination
# Pagination (beta)

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

Expand All @@ -14,14 +14,26 @@ def list_users(request, **kwargs):
return User.objects.all()
```

Note: once you applied pagination - you need also add `**kwargs` parameters to your function (it will store pagination filters)
!!! note
Once you applied pagination - you need also add `**kwargs` parameters to your function (it will store pagination filters)

That's it!

Now you can query users with `limit` and `offset` GET parameters

```
/api/users?limit=10&offset=0
```

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


## Built in Pagination Classes

### LimitOffsetPagination (default)

This is the default pagination class (You can change it in your settings.py using `NINJA_PAGINATION_CLASS` path to a class)

```Python hl_lines="1 4"
from ninja.pagination import paginate, LimitOffsetPagination

Expand All @@ -31,6 +43,17 @@ def list_users(request, **kwargs):
return User.objects.all()
```

Example query:
```
/api/users?limit=10&offset=0
```

this class has two input parameters:

- `limit` - defines a number of items on the page (default = 100, change in NINJA_PAGINATION_PER_PAGE)
- `offset` - set's the page window offset (default: 0, indexing starts with 0)


### PageNumberPagination
```Python hl_lines="1 4"
from ninja.pagination import paginate, PageNumberPagination
Expand All @@ -41,16 +64,34 @@ def list_users(request, **kwargs):
return User.objects.all()
```

Example query:
```
/api/users?page=2
```

this class has one parameter `page` and outputs 100 items per page by default (can be changed with settings.py)

Page numbering start with 1

you can also set custom per_page value individually per view:

```Python hl_lines="2"
@api.get("/users")
@paginate(PageNumberPagination, per_page=50)
def list_users(...
```




## Creating Custom Pagination Class

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

- 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).
- 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 arugments:
- 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:
- `items`: a queryset (or iterable) returned by the api function
- `reques`: django http request object
- `request`: django http request object
- `**params`: kwargs that will contain all the arguments that decorated function recieved (to access pagination input get `params["pagination"]` - it will be a validated instance of your `Input` class)


Expand All @@ -75,4 +116,4 @@ class CustomPagination(PaginationBase):
@paginate(CustomPagination)
def list_users(request, **kwargs):
return User.objects.all()
```
```
12 changes: 7 additions & 5 deletions ninja/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ def view_with_pagination(request: HttpRequest, **kw: DictStrAny) -> Any:
items = func(request, **kw)
return paginator.paginate_queryset(items, request, **kw)

view_with_pagination._ninja_contribute = ( # type: ignore
"pagination",
paginator.Input,
paginator.InputSource,
)
view_with_pagination._ninja_contribute_args = [ # type: ignore
(
"pagination",
paginator.Input,
paginator.InputSource,
),
]

return view_with_pagination
8 changes: 4 additions & 4 deletions ninja/signature/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ def __init__(self, path: str, view_func: Callable) -> None:
func_param = self._get_param_type(name, arg)
self.params.append(func_param)

if hasattr(view_func, "_ninja_contribute"):
# _ninja_contribute is a special attribute
if hasattr(view_func, "_ninja_contribute_args"):
# _ninja_contribute_args is a special attribute
# which allows developers to create custom function params
# inside decorators or other functions
p_name, p_type, p_source = view_func._ninja_contribute # type: ignore
self.params.append(FuncParam(p_name, p_source, p_type, False))
for p_name, p_type, p_source in view_func._ninja_contribute_args: # type: ignore
self.params.append(FuncParam(p_name, p_source, p_type, False))

self.models = self._create_models()

Expand Down

0 comments on commit c8e07b1

Please sign in to comment.