djresttoolkit 0.15.0__py3-none-any.whl → 0.16.1__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
@@ -6,13 +6,53 @@
6
6
 
7
7
  djresttoolkit is a collection of utilities and helpers for Django and Django REST Framework (DRF) that simplify common development tasks such as API handling, authentication, and email sending and much more.
8
8
 
9
- ## Features
9
+ ## 📖 Feature Index (djresttoolkit)
10
10
 
11
- - Django REST Framework helpers (serializers, views, pagination, etc.)
12
- - Django utilities (e.g., email sending, model mixins)
13
- - Ready-to-use shortcuts to speed up API development
14
- - Lightweight, no unnecessary dependencies
15
- - Type Safe - written with modern Python type hints.
11
+ - **DB Seed Command (`dbseed`)**
12
+ Seed your database with fake data using Pydantic models powered by **Faker**. Supports relationships, transactions, and a `manage.py dbseed` command.
13
+
14
+ - **DB Flush Command (`dbflush`)**
15
+ Management command to flush all models or a specific model, resetting auto-increment IDs safely with transaction support.
16
+
17
+ - **EnvBaseSettings**
18
+ Typed settings loader using **YAML + .env**, supports nested keys and overrides. Great for structured configuration management.
19
+
20
+ - **EmailSender**
21
+ Custom class to send templated emails (`text` and `html`) with context. Supports error handling and logging.
22
+
23
+ - **Custom DRF Exception Handler**
24
+ Centralized error handler for DRF that extends default behavior and adds throttle support (`429 Too Many Requests` with retry info).
25
+
26
+ - **Response Time Middleware**
27
+ Middleware to measure, log, and inject `X-Response-Time` headers into every response.
28
+
29
+ - **Throttle**
30
+ - `ThrottleInfoJSONRenderer`: Automatically adds throttle headers to responses.
31
+ - `ThrottleInspector`: Inspect view/request throttling and attach structured headers.
32
+
33
+ - **AbsoluteUrlFileMixin**
34
+ DRF serializer mixin that converts `FileField` / `ImageField` URLs to **absolute URLs** automatically.
35
+
36
+ - **BulkCreateMixin**
37
+ Serializer mixin that enables **bulk creation** of objects and syncs field error messages with model fields.
38
+
39
+ - **ModelChoiceFieldMixin**
40
+ Retrieve choice fields (`TextChoices`, etc.) from Django models as structured dictionaries for API responses.
41
+
42
+ - **ChoiceFieldsAPIView**
43
+ Generic API view that exposes model `choices` in a REST-friendly JSON format.
44
+
45
+ - **RetrieveObjectMixin**
46
+ Lightweight mixin to fetch a single object from a queryset with filters, raising a custom error if `queryset` is not defined.
47
+
48
+ - **build\_absolute\_uri**
49
+ Helper to build full absolute URLs for named routes with optional query params. Works with Django + DRF requests.
50
+
51
+ - **PageNumberPagination**
52
+ Custom paginator with a structured `"page"` metadata block and support for dynamic `page-size` query param.
53
+
54
+ - **PaginatedDataBuilder**
55
+ Builder that combines `PageNumberPagination` + serializers to return standardized paginated responses with `"page"` + `"results"`.
16
56
 
17
57
  ## 📦 Installation
18
58
 
@@ -30,7 +70,7 @@ djresttoolkit is a collection of utilities and helpers for Django and Django RES
30
70
 
31
71
  ## 📚 All API Reference
32
72
 
33
- ### 1. DB Seed Utilities — API Reference
73
+ ### 1. DB Seed Command — API Reference
34
74
 
35
75
  #### `Generator`
36
76
 
@@ -353,7 +393,7 @@ X-Response-Time: 0.01234 seconds
353
393
  INFO: Request processed in 0.01234 seconds
354
394
  ```
355
395
 
356
- ### 7. Throttle Utilities — API Reference
396
+ ### 7. Throttle — API Reference
357
397
 
358
398
  #### `ThrottleInfoJSONRenderer`
359
399
 
@@ -866,6 +906,73 @@ from djresttoolkit.pagination import PageNumberPagination
866
906
  }
867
907
  ```
868
908
 
909
+ ### 15. PaginatedDataBuilder — API Reference
910
+
911
+ ```python
912
+ from djresttoolkit.pagination import PaginatedDataBuilder
913
+ ```
914
+
915
+ ---
916
+
917
+ #### Description of Paginated Data Builder
918
+
919
+ - A **builder utility** to paginate and serialize Django QuerySets using DRF.
920
+ - Uses the custom **`PageNumberPagination`** class for consistent pagination responses.
921
+ - Designed for reusability inside DRF views and APIs.
922
+
923
+ #### Features of Paginated Data Builder
924
+
925
+ - Integrates with **DRF serializers**.
926
+ - Handles **invalid pages** gracefully by raising `NotFound`.
927
+ - Returns both:
928
+ - `"page"` → pagination metadata
929
+ - `"results"` → serialized data.
930
+ - Provides **structured pagination response format**.
931
+
932
+ ---
933
+
934
+ #### Initialization of Paginated Data Builder
935
+
936
+ ```python
937
+ builder = PaginatedDataBuilder(
938
+ request=request,
939
+ serializer_class=MySerializer,
940
+ queryset=MyModel.objects.all()
941
+ )
942
+ ```
943
+
944
+ - `request: Request` → DRF request object.
945
+ - `serializer_class: type[BaseSerializer]` → DRF serializer class for the model.
946
+ - `queryset: QuerySet` → Django queryset to paginate.
947
+
948
+ ### Paginated Data Builder Methods
949
+
950
+ - `get_paginated_data() -> dict[str, Any]`
951
+
952
+ - Applies pagination to the queryset.
953
+ - Serializes the paginated results.
954
+ - Returns a dictionary with `"page"` and `"results"`.
955
+ - Raises `NotFound` if no page data is found.
956
+
957
+ ### Example Response of Paginated Data Builder
958
+
959
+ ```json
960
+ {
961
+ "page": {
962
+ "current": 2,
963
+ "total": 5,
964
+ "size": 20,
965
+ "total_items": 100,
966
+ "next": "http://api.example.com/items/?page=3&page-size=20",
967
+ "previous": "http://api.example.com/items/?page=1&page-size=20"
968
+ },
969
+ "results": [
970
+ { "id": 21, "name": "Item 21" },
971
+ { "id": 22, "name": "Item 22" }
972
+ ]
973
+ }
974
+ ```
975
+
869
976
  ## 🛠️ Planned Features
870
977
 
871
978
  - 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.1
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
@@ -64,13 +64,53 @@ Description-Content-Type: text/markdown
64
64
 
65
65
  djresttoolkit is a collection of utilities and helpers for Django and Django REST Framework (DRF) that simplify common development tasks such as API handling, authentication, and email sending and much more.
66
66
 
67
- ## Features
67
+ ## 📖 Feature Index (djresttoolkit)
68
68
 
69
- - Django REST Framework helpers (serializers, views, pagination, etc.)
70
- - Django utilities (e.g., email sending, model mixins)
71
- - Ready-to-use shortcuts to speed up API development
72
- - Lightweight, no unnecessary dependencies
73
- - Type Safe - written with modern Python type hints.
69
+ - **DB Seed Command (`dbseed`)**
70
+ Seed your database with fake data using Pydantic models powered by **Faker**. Supports relationships, transactions, and a `manage.py dbseed` command.
71
+
72
+ - **DB Flush Command (`dbflush`)**
73
+ Management command to flush all models or a specific model, resetting auto-increment IDs safely with transaction support.
74
+
75
+ - **EnvBaseSettings**
76
+ Typed settings loader using **YAML + .env**, supports nested keys and overrides. Great for structured configuration management.
77
+
78
+ - **EmailSender**
79
+ Custom class to send templated emails (`text` and `html`) with context. Supports error handling and logging.
80
+
81
+ - **Custom DRF Exception Handler**
82
+ Centralized error handler for DRF that extends default behavior and adds throttle support (`429 Too Many Requests` with retry info).
83
+
84
+ - **Response Time Middleware**
85
+ Middleware to measure, log, and inject `X-Response-Time` headers into every response.
86
+
87
+ - **Throttle**
88
+ - `ThrottleInfoJSONRenderer`: Automatically adds throttle headers to responses.
89
+ - `ThrottleInspector`: Inspect view/request throttling and attach structured headers.
90
+
91
+ - **AbsoluteUrlFileMixin**
92
+ DRF serializer mixin that converts `FileField` / `ImageField` URLs to **absolute URLs** automatically.
93
+
94
+ - **BulkCreateMixin**
95
+ Serializer mixin that enables **bulk creation** of objects and syncs field error messages with model fields.
96
+
97
+ - **ModelChoiceFieldMixin**
98
+ Retrieve choice fields (`TextChoices`, etc.) from Django models as structured dictionaries for API responses.
99
+
100
+ - **ChoiceFieldsAPIView**
101
+ Generic API view that exposes model `choices` in a REST-friendly JSON format.
102
+
103
+ - **RetrieveObjectMixin**
104
+ Lightweight mixin to fetch a single object from a queryset with filters, raising a custom error if `queryset` is not defined.
105
+
106
+ - **build\_absolute\_uri**
107
+ Helper to build full absolute URLs for named routes with optional query params. Works with Django + DRF requests.
108
+
109
+ - **PageNumberPagination**
110
+ Custom paginator with a structured `"page"` metadata block and support for dynamic `page-size` query param.
111
+
112
+ - **PaginatedDataBuilder**
113
+ Builder that combines `PageNumberPagination` + serializers to return standardized paginated responses with `"page"` + `"results"`.
74
114
 
75
115
  ## 📦 Installation
76
116
 
@@ -88,7 +128,7 @@ djresttoolkit is a collection of utilities and helpers for Django and Django RES
88
128
 
89
129
  ## 📚 All API Reference
90
130
 
91
- ### 1. DB Seed Utilities — API Reference
131
+ ### 1. DB Seed Command — API Reference
92
132
 
93
133
  #### `Generator`
94
134
 
@@ -411,7 +451,7 @@ X-Response-Time: 0.01234 seconds
411
451
  INFO: Request processed in 0.01234 seconds
412
452
  ```
413
453
 
414
- ### 7. Throttle Utilities — API Reference
454
+ ### 7. Throttle — API Reference
415
455
 
416
456
  #### `ThrottleInfoJSONRenderer`
417
457
 
@@ -924,6 +964,73 @@ from djresttoolkit.pagination import PageNumberPagination
924
964
  }
925
965
  ```
926
966
 
967
+ ### 15. PaginatedDataBuilder — API Reference
968
+
969
+ ```python
970
+ from djresttoolkit.pagination import PaginatedDataBuilder
971
+ ```
972
+
973
+ ---
974
+
975
+ #### Description of Paginated Data Builder
976
+
977
+ - A **builder utility** to paginate and serialize Django QuerySets using DRF.
978
+ - Uses the custom **`PageNumberPagination`** class for consistent pagination responses.
979
+ - Designed for reusability inside DRF views and APIs.
980
+
981
+ #### Features of Paginated Data Builder
982
+
983
+ - Integrates with **DRF serializers**.
984
+ - Handles **invalid pages** gracefully by raising `NotFound`.
985
+ - Returns both:
986
+ - `"page"` → pagination metadata
987
+ - `"results"` → serialized data.
988
+ - Provides **structured pagination response format**.
989
+
990
+ ---
991
+
992
+ #### Initialization of Paginated Data Builder
993
+
994
+ ```python
995
+ builder = PaginatedDataBuilder(
996
+ request=request,
997
+ serializer_class=MySerializer,
998
+ queryset=MyModel.objects.all()
999
+ )
1000
+ ```
1001
+
1002
+ - `request: Request` → DRF request object.
1003
+ - `serializer_class: type[BaseSerializer]` → DRF serializer class for the model.
1004
+ - `queryset: QuerySet` → Django queryset to paginate.
1005
+
1006
+ ### Paginated Data Builder Methods
1007
+
1008
+ - `get_paginated_data() -> dict[str, Any]`
1009
+
1010
+ - Applies pagination to the queryset.
1011
+ - Serializes the paginated results.
1012
+ - Returns a dictionary with `"page"` and `"results"`.
1013
+ - Raises `NotFound` if no page data is found.
1014
+
1015
+ ### Example Response of Paginated Data Builder
1016
+
1017
+ ```json
1018
+ {
1019
+ "page": {
1020
+ "current": 2,
1021
+ "total": 5,
1022
+ "size": 20,
1023
+ "total_items": 100,
1024
+ "next": "http://api.example.com/items/?page=3&page-size=20",
1025
+ "previous": "http://api.example.com/items/?page=1&page-size=20"
1026
+ },
1027
+ "results": [
1028
+ { "id": 21, "name": "Item 21" },
1029
+ { "id": 22, "name": "Item 22" }
1030
+ ]
1031
+ }
1032
+ ```
1033
+
927
1034
  ## 🛠️ Planned Features
928
1035
 
929
1036
  - 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=67zRUEO0Ccp-TqVpe3FsgHqRi5JGfckiZlAjLyI2jSw,26809
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.1.dist-info/METADATA,sha256=-GXgWkX-WeP5Mo3t1Id8QjeQnJWtHNts4PEAjahmePE,29819
50
+ djresttoolkit-0.16.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
+ djresttoolkit-0.16.1.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
52
+ djresttoolkit-0.16.1.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
53
+ djresttoolkit-0.16.1.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