Skip to content

Commit 1c4e518

Browse files
pushpit kambojpushpitkamboj
authored andcommitted
[feature] Added OpenWispPagination class with suitable default values
1 parent 9f2ab62 commit 1c4e518

3 files changed

Lines changed: 117 additions & 0 deletions

File tree

docs/developer/other-utilities.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,45 @@ Every openwisp module which has an API should use this class to configure
8383
its own default settings, which will be merged with the settings of the
8484
other modules.
8585

86+
``openwisp_utils.api.pagination.OpenWispPagination``
87+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88+
89+
A reusable pagination class for DRF views that provides consistent
90+
pagination behavior across OpenWISP modules with sensible defaults.
91+
92+
- **10** items per page (``page_size``)
93+
- **100** max items per page (``max_page_size``)
94+
- Custom page size via ``?page_size=N`` query parameter
95+
96+
**Usage in Views:**
97+
98+
.. code-block:: python
99+
100+
from openwisp_utils.api.pagination import OpenWispPagination
101+
from rest_framework.viewsets import ModelViewSet
102+
103+
104+
class DeviceViewSet(ModelViewSet):
105+
queryset = Device.objects.all()
106+
serializer_class = DeviceSerializer
107+
pagination_class = OpenWispPagination
108+
109+
**API Request Examples:**
110+
111+
.. code-block:: bash
112+
113+
# Returns first 10 items (default page size)
114+
GET /api/v1/controller/devices/
115+
116+
# Returns items 11-20 (second page)
117+
GET /api/v1/controller/devices/?page=2
118+
119+
# Returns first 25 items (custom page size)
120+
GET /api/v1/controller/devices/?page_size=25
121+
122+
# Returns items 26-50 with custom page size
123+
GET /api/v1/controller/devices/?page=2&page_size=25
124+
86125
Storage Utilities
87126
-----------------
88127

openwisp_utils/api/pagination.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django.core.exceptions import ImproperlyConfigured
2+
3+
try:
4+
from rest_framework.pagination import PageNumberPagination
5+
except ImportError: # pragma: nocover
6+
raise ImproperlyConfigured(
7+
"Django REST Framework is required to use "
8+
"this feature but it is not installed"
9+
)
10+
11+
12+
class OpenWispPagination(PageNumberPagination):
13+
"""Reusable pagination class with sensible defaults."""
14+
15+
page_size = 10
16+
max_page_size = 100
17+
page_size_query_param = "page_size"

tests/test_project/tests/test_api.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from django.conf import settings
22
from django.core.exceptions import ValidationError
33
from django.test import TestCase
4+
from openwisp_utils.api.pagination import OpenWispPagination
5+
from rest_framework.pagination import PageNumberPagination
6+
from rest_framework.request import Request
7+
from rest_framework.test import APIRequestFactory
48
from test_project.serializers import ShelfSerializer
59

610
from ..models import Shelf
@@ -64,3 +68,60 @@ def test_rest_framework_settings_override(self):
6468
"TEST": True,
6569
},
6670
)
71+
72+
73+
class TestOpenWispPagination(CreateMixin, TestCase):
74+
shelf_model = Shelf
75+
76+
def setUp(self):
77+
self.factory = APIRequestFactory()
78+
self.pagination = OpenWispPagination()
79+
for i in range(15):
80+
self._create_shelf(name=f"shelf{i}")
81+
82+
def _get_request(self, path="/api/shelves/", data=None):
83+
return Request(self.factory.get(path, data))
84+
85+
def test_inheritance(self):
86+
self.assertIsInstance(self.pagination, PageNumberPagination)
87+
88+
def test_default_attributes(self):
89+
self.assertEqual(self.pagination.page_size, 10)
90+
self.assertEqual(self.pagination.max_page_size, 100)
91+
self.assertEqual(self.pagination.page_size_query_param, "page_size")
92+
93+
def test_paginate_queryset(self):
94+
request = self._get_request()
95+
queryset = Shelf.objects.all().order_by("id")
96+
paginated = self.pagination.paginate_queryset(queryset, request)
97+
self.assertEqual(len(paginated), 10)
98+
99+
def test_paginate_queryset_second_page(self):
100+
request = self._get_request(data={"page": 2})
101+
queryset = Shelf.objects.all().order_by("id")
102+
paginated = self.pagination.paginate_queryset(queryset, request)
103+
self.assertEqual(len(paginated), 5)
104+
105+
def test_paginate_queryset_custom_page_size(self):
106+
request = self._get_request(data={"page_size": 5})
107+
queryset = Shelf.objects.all().order_by("id")
108+
paginated = self.pagination.paginate_queryset(queryset, request)
109+
self.assertEqual(len(paginated), 5)
110+
111+
def test_paginate_queryset_respects_max_page_size(self):
112+
self.pagination.max_page_size = 10
113+
request = self._get_request(data={"page_size": 100})
114+
queryset = Shelf.objects.all().order_by("id")
115+
paginated = self.pagination.paginate_queryset(queryset, request)
116+
self.assertEqual(len(paginated), 10)
117+
118+
def test_get_paginated_response(self):
119+
request = self._get_request()
120+
queryset = Shelf.objects.all().order_by("id")
121+
self.pagination.paginate_queryset(queryset, request)
122+
response = self.pagination.get_paginated_response([])
123+
self.assertIn("count", response.data)
124+
self.assertIn("next", response.data)
125+
self.assertIn("previous", response.data)
126+
self.assertIn("results", response.data)
127+
self.assertEqual(response.data["count"], 15)

0 commit comments

Comments
 (0)