djresttoolkit 0.15.0__py3-none-any.whl → 0.16.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
README.md CHANGED
@@ -866,6 +866,73 @@ from djresttoolkit.pagination import PageNumberPagination
866
866
  }
867
867
  ```
868
868
 
869
+ ### 15. PaginatedDataBuilder — API Reference
870
+
871
+ ```python
872
+ from djresttoolkit.pagination import PaginatedDataBuilder
873
+ ```
874
+
875
+ ---
876
+
877
+ #### Description of Paginated Data Builder
878
+
879
+ - A **builder utility** to paginate and serialize Django QuerySets using DRF.
880
+ - Uses the custom **`PageNumberPagination`** class for consistent pagination responses.
881
+ - Designed for reusability inside DRF views and APIs.
882
+
883
+ #### Features of Paginated Data Builder
884
+
885
+ - Integrates with **DRF serializers**.
886
+ - Handles **invalid pages** gracefully by raising `NotFound`.
887
+ - Returns both:
888
+ - `"page"` → pagination metadata
889
+ - `"results"` → serialized data.
890
+ - Provides **structured pagination response format**.
891
+
892
+ ---
893
+
894
+ #### Initialization of Paginated Data Builder
895
+
896
+ ```python
897
+ builder = PaginatedDataBuilder(
898
+ request=request,
899
+ serializer_class=MySerializer,
900
+ queryset=MyModel.objects.all()
901
+ )
902
+ ```
903
+
904
+ - `request: Request` → DRF request object.
905
+ - `serializer_class: type[BaseSerializer]` → DRF serializer class for the model.
906
+ - `queryset: QuerySet` → Django queryset to paginate.
907
+
908
+ ### Paginated Data Builder Methods
909
+
910
+ - `get_paginated_data() -> dict[str, Any]`
911
+
912
+ - Applies pagination to the queryset.
913
+ - Serializes the paginated results.
914
+ - Returns a dictionary with `"page"` and `"results"`.
915
+ - Raises `NotFound` if no page data is found.
916
+
917
+ ### Example Response of Paginated Data Builder
918
+
919
+ ```json
920
+ {
921
+ "page": {
922
+ "current": 2,
923
+ "total": 5,
924
+ "size": 20,
925
+ "total_items": 100,
926
+ "next": "http://api.example.com/items/?page=3&page-size=20",
927
+ "previous": "http://api.example.com/items/?page=1&page-size=20"
928
+ },
929
+ "results": [
930
+ { "id": 21, "name": "Item 21" },
931
+ { "id": 22, "name": "Item 22" }
932
+ ]
933
+ }
934
+ ```
935
+
869
936
  ## 🛠️ Planned Features
870
937
 
871
938
  - Add more utils
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djresttoolkit
3
- Version: 0.15.0
3
+ Version: 0.16.0
4
4
  Summary: A collection of Django and DRF utilities to simplify API development.
5
5
  Project-URL: Homepage, https://github.com/shaileshpandit141/djresttoolkit
6
6
  Project-URL: Documentation, https://shaileshpandit141.github.io/djresttoolkit
@@ -924,6 +924,73 @@ from djresttoolkit.pagination import PageNumberPagination
924
924
  }
925
925
  ```
926
926
 
927
+ ### 15. PaginatedDataBuilder — API Reference
928
+
929
+ ```python
930
+ from djresttoolkit.pagination import PaginatedDataBuilder
931
+ ```
932
+
933
+ ---
934
+
935
+ #### Description of Paginated Data Builder
936
+
937
+ - A **builder utility** to paginate and serialize Django QuerySets using DRF.
938
+ - Uses the custom **`PageNumberPagination`** class for consistent pagination responses.
939
+ - Designed for reusability inside DRF views and APIs.
940
+
941
+ #### Features of Paginated Data Builder
942
+
943
+ - Integrates with **DRF serializers**.
944
+ - Handles **invalid pages** gracefully by raising `NotFound`.
945
+ - Returns both:
946
+ - `"page"` → pagination metadata
947
+ - `"results"` → serialized data.
948
+ - Provides **structured pagination response format**.
949
+
950
+ ---
951
+
952
+ #### Initialization of Paginated Data Builder
953
+
954
+ ```python
955
+ builder = PaginatedDataBuilder(
956
+ request=request,
957
+ serializer_class=MySerializer,
958
+ queryset=MyModel.objects.all()
959
+ )
960
+ ```
961
+
962
+ - `request: Request` → DRF request object.
963
+ - `serializer_class: type[BaseSerializer]` → DRF serializer class for the model.
964
+ - `queryset: QuerySet` → Django queryset to paginate.
965
+
966
+ ### Paginated Data Builder Methods
967
+
968
+ - `get_paginated_data() -> dict[str, Any]`
969
+
970
+ - Applies pagination to the queryset.
971
+ - Serializes the paginated results.
972
+ - Returns a dictionary with `"page"` and `"results"`.
973
+ - Raises `NotFound` if no page data is found.
974
+
975
+ ### Example Response of Paginated Data Builder
976
+
977
+ ```json
978
+ {
979
+ "page": {
980
+ "current": 2,
981
+ "total": 5,
982
+ "size": 20,
983
+ "total_items": 100,
984
+ "next": "http://api.example.com/items/?page=3&page-size=20",
985
+ "previous": "http://api.example.com/items/?page=1&page-size=20"
986
+ },
987
+ "results": [
988
+ { "id": 21, "name": "Item 21" },
989
+ { "id": 22, "name": "Item 22" }
990
+ ]
991
+ }
992
+ ```
993
+
927
994
  ## 🛠️ Planned Features
928
995
 
929
996
  - Add more utils
@@ -1,5 +1,5 @@
1
1
  LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
2
- README.md,sha256=I7qkoMQKLheto6lBClF21nbUqjIoQL84mJeopKxJxgQ,23157
2
+ README.md,sha256=wdjszjenN8a6p1wcJSfaIbhjlZgretrF_Y3XSMwyQsQ,24856
3
3
  demo/staticfiles/admin/img/LICENSE,sha256=0RT6_zSIwWwxmzI13EH5AjnT1j2YU3MwM9j3U19cAAQ,1081
4
4
  src/djresttoolkit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  src/djresttoolkit/admin.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -26,8 +26,9 @@ src/djresttoolkit/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
26
26
  src/djresttoolkit/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  src/djresttoolkit/models/mixins/__init__.py,sha256=MHwv36f3nHwI0bXeejuO7MTYuV93ln2tSyCCipS2xVw,223
28
28
  src/djresttoolkit/models/mixins/_model_choice_fields_mixin.py,sha256=9FZbe3PwrtIUZYGQh1gcOix5bfeyvKEOaNmkemvZX8E,2843
29
- src/djresttoolkit/pagination/__init__.py,sha256=_Kb6oY2Aod6r4RYhmK0kmyiBdL0Dg-w15b9egtLdMMA,94
29
+ src/djresttoolkit/pagination/__init__.py,sha256=lQhyyX381RbWBsYV9Os3OQIbY7Z6aouL0QE5kI_u5SU,176
30
30
  src/djresttoolkit/pagination/_page_number_pagination.py,sha256=NHPdMZfmTurKLdgpMBT2usTiGAoZMyA3dYXq_n11y34,2358
31
+ src/djresttoolkit/pagination/_paginated_data_builder.py,sha256=N4JaJwmfmC2NiC8MqOpkxV8-itKTueaOdawnv_it4bU,2239
31
32
  src/djresttoolkit/renderers/__init__.py,sha256=kmFMPRiMfD8CuJTN1_-6Z_Hqil3x8GBM0IN1roZESm0,107
32
33
  src/djresttoolkit/renderers/_throttle_info_json_renderer.py,sha256=aP2cN4cB_Imcpy732zsPBQrMQqcKEs5R3dld5Y_4AMU,1089
33
34
  src/djresttoolkit/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -45,8 +46,8 @@ src/djresttoolkit/views/_exceptions/__init__.py,sha256=DrCUxuPNyBR4WhzNutn5HDxLa
45
46
  src/djresttoolkit/views/_exceptions/_exception_handler.py,sha256=_o7If47bzWLl57LeSXSWsIDsJGo2RIpwYAwNQ-hsHVY,2839
46
47
  src/djresttoolkit/views/mixins/__init__.py,sha256=K-1tk5d8tCVViMynw5DdffJ3Oo5uHpEx32E3_4X2UxM,154
47
48
  src/djresttoolkit/views/mixins/_retrieve_object_mixin.py,sha256=Q9znYPb07YXXUhsL7VIrk3BC-zDwjOhwLJKe2GPJ-k0,1155
48
- djresttoolkit-0.15.0.dist-info/METADATA,sha256=zrnyfZFOoLT9ZcY179fBwk4j4xJjvTFWQRburyaeOxc,26167
49
- djresttoolkit-0.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
50
- djresttoolkit-0.15.0.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
51
- djresttoolkit-0.15.0.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
52
- djresttoolkit-0.15.0.dist-info/RECORD,,
49
+ djresttoolkit-0.16.0.dist-info/METADATA,sha256=wHoVJ4XBAJVLoZYMPC-2Q7QrlwXuguGbnHvbmIG9iMM,27866
50
+ djresttoolkit-0.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
+ djresttoolkit-0.16.0.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
52
+ djresttoolkit-0.16.0.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
53
+ djresttoolkit-0.16.0.dist-info/RECORD,,
@@ -1,3 +1,4 @@
1
1
  from ._page_number_pagination import PageNumberPagination
2
+ from ._paginated_data_builder import PaginatedDataBuilder
2
3
 
3
- __all__ = ["PageNumberPagination"]
4
+ __all__ = ["PageNumberPagination", "PaginatedDataBuilder"]
@@ -0,0 +1,65 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ from django.db.models import QuerySet
5
+ from rest_framework.exceptions import NotFound
6
+ from rest_framework.request import Request
7
+ from rest_framework.serializers import BaseSerializer
8
+ from django.db.models import Model
9
+ from ._page_number_pagination import PageNumberPagination
10
+
11
+ # Get logger from logging.
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class PaginatedDataBuilder[T: Model]:
16
+ """Builder class to handle pagination and serialization."""
17
+
18
+ def __init__(
19
+ self,
20
+ request: Request,
21
+ serializer_class: type[BaseSerializer[T]],
22
+ queryset: QuerySet[T],
23
+ ) -> None:
24
+ """Initilize the PaginatedDataBuilder class."""
25
+ self.request = request
26
+ self.serializer_class = serializer_class
27
+ self.queryset = queryset
28
+
29
+ def get_paginated_data(self) -> dict[str, Any]:
30
+ """Paginate and serialize the queryset."""
31
+
32
+ logger.debug("Starting pagination with custom PageNumberPagination.")
33
+ paginator = PageNumberPagination()
34
+ page = paginator.paginate_queryset(
35
+ self.queryset,
36
+ self.request,
37
+ )
38
+
39
+ # If no data is returned from pagination, raise NotFound
40
+ if page is None:
41
+ logger.warning("No data returned from pagination. Possibly invalid page.")
42
+ raise NotFound("The requested records were not found.")
43
+
44
+ # Serialize the paginated data
45
+ serializer = self.serializer_class(
46
+ instance=page, # type: ignore
47
+ many=True,
48
+ context={"request": self.request},
49
+ )
50
+
51
+ # Construct the paginated response
52
+ paginated_data = {
53
+ "page": {
54
+ "current": paginator.page.number, # type: ignore
55
+ "total": paginator.page.paginator.num_pages, # type: ignore
56
+ "size": paginator.get_page_size(self.request),
57
+ "total_items": paginator.page.paginator.count, # type: ignore
58
+ "next": paginator.get_next_link(),
59
+ "previous": paginator.get_previous_link(),
60
+ },
61
+ "results": serializer.data,
62
+ }
63
+
64
+ logger.debug(f"Pagination result: {paginated_data}")
65
+ return paginated_data