Skip to content

Commit cdd3243

Browse files
authored
Merge pull request #1608 from Lokker29/fix-pagination-layers
Fixed pagination override in case of RouterPaginated
2 parents 31c1275 + 71eb590 commit cdd3243

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

ninja/pagination.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ def _inject_pagination(
219219
paginator_class: Type[Union[PaginationBase, AsyncPaginationBase]],
220220
**paginator_params: Any,
221221
) -> Callable[..., Any]:
222+
if getattr(func, "_is_paginated", False):
223+
return func
224+
222225
paginator = paginator_class(**paginator_params)
223226

224227
# Check if Input schema has any fields
@@ -292,6 +295,7 @@ def view_with_pagination(request: HttpRequest, **kwargs: Any) -> Any:
292295
partial(make_response_paginated, paginator),
293296
)
294297

298+
view_with_pagination._is_paginated = True # type: ignore
295299
return view_with_pagination
296300

297301

tests/test_pagination_router.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from ninja import NinjaAPI, Schema
6-
from ninja.pagination import RouterPaginated
6+
from ninja.pagination import PageNumberPagination, RouterPaginated, paginate
77
from ninja.testing import TestAsyncClient, TestClient
88

99
api = NinjaAPI(default_router=RouterPaginated())
@@ -23,6 +23,18 @@ def items_nolist(request):
2323
return {"id": 1}
2424

2525

26+
@api.get("/items_extra_layer", response=List[ItemSchema])
27+
@paginate # has not to break down
28+
def items_extra_layer(request):
29+
return [{"id": i} for i in range(1, 51)]
30+
31+
32+
@api.get("/items_overridden", response=List[ItemSchema])
33+
@paginate(PageNumberPagination, page_size=3) # has precedence over router pagination
34+
def items_overridden_pagination(request):
35+
return [{"id": i} for i in range(1, 51)]
36+
37+
2638
client = TestClient(api)
2739

2840

@@ -66,6 +78,70 @@ def test_for_NON_list_reponse():
6678
assert parameters == []
6779

6880

81+
def test_extra_pagination_layer_does_not_crash():
82+
parameters = api.get_openapi_schema()["paths"]["/api/items_extra_layer"]["get"][
83+
"parameters"
84+
]
85+
assert parameters == [
86+
{
87+
"in": "query",
88+
"name": "limit",
89+
"schema": {
90+
"title": "Limit",
91+
"default": 100,
92+
"minimum": 1,
93+
"type": "integer",
94+
},
95+
"required": False,
96+
},
97+
{
98+
"in": "query",
99+
"name": "offset",
100+
"schema": {
101+
"title": "Offset",
102+
"default": 0,
103+
"minimum": 0,
104+
"type": "integer",
105+
},
106+
"required": False,
107+
},
108+
]
109+
110+
response = client.get("/items_extra_layer?offset=5&limit=1").json()
111+
assert response == {"items": [{"id": 6}], "count": 50}
112+
113+
114+
def test_for_list_with_overridden_pagination_reponse():
115+
parameters = api.get_openapi_schema()["paths"]["/api/items_overridden"]["get"][
116+
"parameters"
117+
]
118+
assert parameters == [
119+
{
120+
"in": "query",
121+
"name": "page",
122+
"schema": {
123+
"title": "Page",
124+
"default": 1,
125+
"minimum": 1,
126+
"type": "integer",
127+
},
128+
"required": False,
129+
},
130+
{
131+
"in": "query",
132+
"name": "page_size",
133+
"schema": {
134+
"anyOf": [{"minimum": 1, "type": "integer"}, {"type": "null"}],
135+
"title": "Page Size",
136+
},
137+
"required": False,
138+
},
139+
]
140+
141+
response = client.get("/items_overridden?page=5").json()
142+
assert response == {"items": [{"id": 13}, {"id": 14}, {"id": 15}], "count": 50}
143+
144+
69145
@pytest.mark.asyncio
70146
async def test_async_pagination():
71147
@api.get("/items_async", response=List[ItemSchema])

0 commit comments

Comments
 (0)