From e6909350d8f0c2e19b31dee26525aeaf6181bf3e Mon Sep 17 00:00:00 2001 From: Ali RajabNezhad Date: Fri, 29 Mar 2024 00:35:03 +0330 Subject: [PATCH] Split `paginate` and `template` in `Pagination` --- docs/docs/release_notes.md | 1 + panther/app.py | 2 ++ panther/generics.py | 10 +++++----- panther/pagination.py | 7 +++++-- panther/response.py | 5 +++++ 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/docs/release_notes.md b/docs/docs/release_notes.md index 5569fbf..242e3ff 100644 --- a/docs/docs/release_notes.md +++ b/docs/docs/release_notes.md @@ -1,5 +1,6 @@ ### 4.1.1 - Fix an issue in `Response.prepare_data()` when `data` is `Cursor` +- Split `paginate` and `template` in `Pagination` ### 4.1.0 - Support `prepare_response` in `Serializers` diff --git a/panther/app.py b/panther/app.py index 611427a..82c523e 100644 --- a/panther/app.py +++ b/panther/app.py @@ -96,6 +96,8 @@ async def wrapper(request: Request) -> Response: response = Response(data=response) if self.output_model and response.data: response.data = await response.apply_output_model(output_model=self.output_model) + if response.pagination: + response.data = await response.pagination.template(response.data) # 10. Set New Response To Cache if self.cache and self.request.method == 'GET': diff --git a/panther/generics.py b/panther/generics.py index dba5a04..ce6bb6f 100644 --- a/panther/generics.py +++ b/panther/generics.py @@ -65,10 +65,10 @@ class ListAPI(GenericAPI, CursorRequired): pagination: type[Pagination] async def get(self, request: Request, **kwargs): - cursor = await self.prepare_cursor(request=request, **kwargs) - return Response(data=cursor, status_code=status.HTTP_200_OK) + cursor, pagination = await self.prepare_cursor(request=request, **kwargs) + return Response(data=cursor, pagination=pagination, status_code=status.HTTP_200_OK) - async def prepare_cursor(self, request: Request, **kwargs): + async def prepare_cursor(self, request: Request, **kwargs) -> tuple[Cursor | PantherDBCursor, Pagination | None]: cursor = await self.cursor(request=request, **kwargs) self._check_cursor(cursor) @@ -83,9 +83,9 @@ async def prepare_cursor(self, request: Request, **kwargs): cursor = cursor.sort(sort) if pagination := self.process_pagination(query_params=request.query_params, cursor=cursor): - cursor = await pagination.paginate() + cursor = pagination.paginate() - return cursor + return cursor, pagination def process_filters(self, query_params: dict, cursor: Cursor | PantherDBCursor) -> dict: _filter = {} diff --git a/panther/pagination.py b/panther/pagination.py index 6cb70fd..de2e272 100644 --- a/panther/pagination.py +++ b/panther/pagination.py @@ -36,7 +36,10 @@ def build_previous_params(self): previous_skip = max(self.skip - self.limit, 0) return f'?limit={self.limit}&skip={previous_skip}' - async def paginate(self): + def paginate(self): + return self.cursor.skip(skip=self.skip).limit(limit=self.limit) + + async def template(self, response: list): count = await self.cursor.cls.count(self.cursor.filter) has_next = not bool(self.limit + self.skip >= count) @@ -44,5 +47,5 @@ async def paginate(self): 'count': count, 'next': self.build_next_params() if has_next else None, 'previous': self.build_previous_params() if self.skip else None, - 'results': self.cursor.skip(skip=self.skip).limit(limit=self.limit) + 'results': response } diff --git a/panther/response.py b/panther/response.py index 0436a96..2cf49fa 100644 --- a/panther/response.py +++ b/panther/response.py @@ -10,6 +10,7 @@ from panther.db.cursor import Cursor from pantherdb import Cursor as PantherDBCursor from panther.monitoring import Monitoring +from panther.pagination import Pagination ResponseDataTypes = list | tuple | set | Cursor | PantherDBCursor | dict | int | float | str | bool | bytes | NoneType | Type[BaseModel] IterableDataTypes = list | tuple | set | Cursor | PantherDBCursor @@ -24,13 +25,17 @@ def __init__( data: ResponseDataTypes = None, headers: dict | None = None, status_code: int = status.HTTP_200_OK, + pagination: Pagination | None = None, ): """ :param data: should be an instance of ResponseDataTypes :param headers: should be dict of headers :param status_code: should be int + :param pagination: instance of Pagination or None + Its template() method will be used """ self.headers = headers or {} + self.pagination: Pagination | None = pagination if isinstance(data, Cursor): data = list(data) self.initial_data = data