djresttoolkit 1.1.0__py3-none-any.whl → 1.2.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.
- djresttoolkit/pagination/_paginated_data_builder.py +10 -4
- djresttoolkit/serializers/__init__.py +3 -0
- djresttoolkit/serializers/_enhanced_model_serializer.py +59 -0
- {djresttoolkit-1.1.0.dist-info → djresttoolkit-1.2.1.dist-info}/METADATA +30 -5
- {djresttoolkit-1.1.0.dist-info → djresttoolkit-1.2.1.dist-info}/RECORD +8 -7
- {djresttoolkit-1.1.0.dist-info → djresttoolkit-1.2.1.dist-info}/WHEEL +0 -0
- {djresttoolkit-1.1.0.dist-info → djresttoolkit-1.2.1.dist-info}/entry_points.txt +0 -0
- {djresttoolkit-1.1.0.dist-info → djresttoolkit-1.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,13 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import Any
|
3
3
|
|
4
|
-
from django.db.models import QuerySet
|
4
|
+
from django.db.models import Model, QuerySet
|
5
5
|
from rest_framework.exceptions import NotFound
|
6
6
|
from rest_framework.request import Request
|
7
7
|
from rest_framework.serializers import BaseSerializer
|
8
|
-
|
8
|
+
|
9
|
+
from djresttoolkit.serializers import EnhancedModelSerializer
|
10
|
+
|
9
11
|
from ._page_number_pagination import PageNumberPagination
|
10
12
|
|
11
13
|
# Get logger from logging.
|
@@ -18,7 +20,7 @@ class PaginatedDataBuilder[T: Model]:
|
|
18
20
|
def __init__(
|
19
21
|
self,
|
20
22
|
request: Request,
|
21
|
-
serializer_class: type[BaseSerializer[T]],
|
23
|
+
serializer_class: type[BaseSerializer[T] | EnhancedModelSerializer[T]],
|
22
24
|
queryset: QuerySet[T],
|
23
25
|
) -> None:
|
24
26
|
"""Initilize the PaginatedDataBuilder class."""
|
@@ -49,7 +51,7 @@ class PaginatedDataBuilder[T: Model]:
|
|
49
51
|
)
|
50
52
|
|
51
53
|
# Construct the paginated response
|
52
|
-
paginated_data = {
|
54
|
+
paginated_data: dict[str, Any] = {
|
53
55
|
"page": {
|
54
56
|
"current": paginator.page.number, # type: ignore
|
55
57
|
"total": paginator.page.paginator.num_pages, # type: ignore
|
@@ -63,3 +65,7 @@ class PaginatedDataBuilder[T: Model]:
|
|
63
65
|
|
64
66
|
logger.debug(f"Pagination result: {paginated_data}")
|
65
67
|
return paginated_data
|
68
|
+
|
69
|
+
@property
|
70
|
+
def paginated_data(self) -> dict[str, Any]:
|
71
|
+
return self.get_paginated_data()
|
@@ -0,0 +1,59 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from copy import deepcopy
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from django.db.models import Field as DjangoField
|
7
|
+
from django.db.models import Model
|
8
|
+
from rest_framework.serializers import Field as DrfField
|
9
|
+
from rest_framework.serializers import ModelSerializer
|
10
|
+
from rest_framework.utils.model_meta import RelationInfo
|
11
|
+
|
12
|
+
|
13
|
+
class EnhancedModelSerializer[T: Model](ModelSerializer[Model]):
|
14
|
+
"""
|
15
|
+
A DRF ModelSerializer that automatically applies Django model field
|
16
|
+
`error_messages` unless explicitly overridden in the serializer.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def _merge_error_messages(
|
20
|
+
self,
|
21
|
+
field_kwargs: dict[str, Any],
|
22
|
+
model_field: DjangoField[Any, Any] | None,
|
23
|
+
) -> dict[str, Any]:
|
24
|
+
"""Safely merge model field error_messages with serializer kwargs."""
|
25
|
+
model_errors: dict[str, str] | None = getattr(
|
26
|
+
model_field, "error_messages", None
|
27
|
+
)
|
28
|
+
if model_errors:
|
29
|
+
existing: dict[str, str] = field_kwargs.get("error_messages", {})
|
30
|
+
field_kwargs["error_messages"] = {**deepcopy(model_errors), **existing}
|
31
|
+
return field_kwargs
|
32
|
+
|
33
|
+
def build_standard_field(
|
34
|
+
self,
|
35
|
+
field_name: str,
|
36
|
+
model_field: DjangoField[Any, Any],
|
37
|
+
) -> tuple[type[DrfField[Any, Any, Any, Any]], dict[str, Any]]:
|
38
|
+
field_class, field_kwargs = super().build_standard_field( # type: ignore
|
39
|
+
field_name,
|
40
|
+
model_field,
|
41
|
+
)
|
42
|
+
return field_class, self._merge_error_messages(
|
43
|
+
field_kwargs,
|
44
|
+
model_field,
|
45
|
+
) # type: ignore
|
46
|
+
|
47
|
+
def build_relational_field(
|
48
|
+
self,
|
49
|
+
field_name: str,
|
50
|
+
relation_info: RelationInfo,
|
51
|
+
) -> tuple[type[DrfField[Any, Any, Any, Any]], dict[str, Any]]:
|
52
|
+
field_class, field_kwargs = super().build_relational_field( # type: ignore
|
53
|
+
field_name,
|
54
|
+
relation_info,
|
55
|
+
)
|
56
|
+
return field_class, self._merge_error_messages(
|
57
|
+
field_kwargs,
|
58
|
+
relation_info.model_field, # type: ignore
|
59
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: djresttoolkit
|
3
|
-
Version: 1.1
|
3
|
+
Version: 1.2.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
|
@@ -970,7 +970,7 @@ from djresttoolkit.pagination import PaginatedDataBuilder
|
|
970
970
|
```python
|
971
971
|
builder = PaginatedDataBuilder(
|
972
972
|
request=request,
|
973
|
-
serializer_class=
|
973
|
+
serializer_class=BookSerializer,
|
974
974
|
queryset=MyModel.objects.all()
|
975
975
|
)
|
976
976
|
```
|
@@ -979,7 +979,7 @@ builder = PaginatedDataBuilder(
|
|
979
979
|
- `serializer_class: type[BaseSerializer]`:- DRF serializer class for the model.
|
980
980
|
- `queryset: QuerySet`:- Django queryset to paginate.
|
981
981
|
|
982
|
-
### Paginated Data Builder Methods
|
982
|
+
### Paginated Data Builder Methods and Property
|
983
983
|
|
984
984
|
- `get_paginated_data() -> dict[str, Any]`
|
985
985
|
|
@@ -987,6 +987,10 @@ builder = PaginatedDataBuilder(
|
|
987
987
|
- Serializes the paginated results.
|
988
988
|
- Returns a dictionary with `"page"` and `"results"`.
|
989
989
|
- Raises `NotFound` if no page data is found.
|
990
|
+
|
991
|
+
- `paginated_data -> dict[str, Any]`
|
992
|
+
|
993
|
+
- Call `paginated_data` property that internaly call `get_paginated_data()` method
|
990
994
|
|
991
995
|
### Example Response of Paginated Data Builder
|
992
996
|
|
@@ -1001,8 +1005,8 @@ builder = PaginatedDataBuilder(
|
|
1001
1005
|
"previous": "http://api.example.com/items/?page=1&page-size=20"
|
1002
1006
|
},
|
1003
1007
|
"results": [
|
1004
|
-
{ "id": 21, "
|
1005
|
-
{ "id": 22, "
|
1008
|
+
{ "id": 21, "title": "Title 21" },
|
1009
|
+
{ "id": 22, "title": "Title 22" }
|
1006
1010
|
]
|
1007
1011
|
}
|
1008
1012
|
```
|
@@ -1081,6 +1085,27 @@ class BookViewSet(CacheInvalidateMixin, ModelViewSet):
|
|
1081
1085
|
- Invalidates caches when books are created, updated, or deleted.
|
1082
1086
|
- Supports custom cache keys per action.
|
1083
1087
|
|
1088
|
+
### 17. EnhancedModelSerializer — API Reference
|
1089
|
+
|
1090
|
+
A subclass of Django REST Framework’s `ModelSerializer` that automatically merges Django model field `error_messages` into the serializer field, unless explicitly overridden.
|
1091
|
+
This helps maintain consistent validation messages between the model and the serializer.
|
1092
|
+
|
1093
|
+
#### Type Parameters
|
1094
|
+
|
1095
|
+
- `T` (`Model`): The Django model type that the serializer corresponds to.
|
1096
|
+
|
1097
|
+
#### Example of EnhancedModelSerializer
|
1098
|
+
|
1099
|
+
```python
|
1100
|
+
from myapp.models import Book
|
1101
|
+
from myapp.serializers import EnhancedModelSerializer
|
1102
|
+
|
1103
|
+
class BookSerializer(EnhancedModelSerializer[Book]):
|
1104
|
+
class Meta:
|
1105
|
+
model = Book
|
1106
|
+
fields = "__all__"
|
1107
|
+
```
|
1108
|
+
|
1084
1109
|
## 🛠️ Planned Features
|
1085
1110
|
|
1086
1111
|
- Add more utils
|
@@ -32,10 +32,11 @@ djresttoolkit/models/mixins/__init__.py,sha256=MHwv36f3nHwI0bXeejuO7MTYuV93ln2tS
|
|
32
32
|
djresttoolkit/models/mixins/_model_choice_fields_mixin.py,sha256=9FZbe3PwrtIUZYGQh1gcOix5bfeyvKEOaNmkemvZX8E,2843
|
33
33
|
djresttoolkit/pagination/__init__.py,sha256=lQhyyX381RbWBsYV9Os3OQIbY7Z6aouL0QE5kI_u5SU,176
|
34
34
|
djresttoolkit/pagination/_page_number_pagination.py,sha256=NHPdMZfmTurKLdgpMBT2usTiGAoZMyA3dYXq_n11y34,2358
|
35
|
-
djresttoolkit/pagination/_paginated_data_builder.py,sha256=
|
35
|
+
djresttoolkit/pagination/_paginated_data_builder.py,sha256=oASu4wA8hN8vaPlh4rx0HM600CUVO179M25JEr9pRx4,2424
|
36
36
|
djresttoolkit/renderers/__init__.py,sha256=kmFMPRiMfD8CuJTN1_-6Z_Hqil3x8GBM0IN1roZESm0,107
|
37
37
|
djresttoolkit/renderers/_throttle_info_json_renderer.py,sha256=aP2cN4cB_Imcpy732zsPBQrMQqcKEs5R3dld5Y_4AMU,1089
|
38
|
-
djresttoolkit/serializers/__init__.py,sha256=
|
38
|
+
djresttoolkit/serializers/__init__.py,sha256=367CLluj8C15Zpr7BD-euP4DxKbwepm58gnGGcuYOJU,103
|
39
|
+
djresttoolkit/serializers/_enhanced_model_serializer.py,sha256=XNYM-zy5_ecfUNRtmBfaDKSuxEDhmoBV9HNx8iSaDpE,2055
|
39
40
|
djresttoolkit/serializers/mixins/__init__.py,sha256=dRT0kXDckOkZo1RQHrT1gXbGFMIv5M8TBHGF2uF-81Q,225
|
40
41
|
djresttoolkit/serializers/mixins/_absolute_url_file_mixin.py,sha256=5ewael0_RsJZ9b36IfXacxjb-Vx1eQ9Dk6dWuj5D_dc,3261
|
41
42
|
djresttoolkit/serializers/mixins/_bulk_create_mixin.py,sha256=9ZWm2MNaZOhmhKlWOu6VECtlDbUtaPeceGHmivDYwYQ,3248
|
@@ -50,8 +51,8 @@ djresttoolkit/views/_exceptions/__init__.py,sha256=DrCUxuPNyBR4WhzNutn5HDxLa--q5
|
|
50
51
|
djresttoolkit/views/_exceptions/_exception_handler.py,sha256=_o7If47bzWLl57LeSXSWsIDsJGo2RIpwYAwNQ-hsHVY,2839
|
51
52
|
djresttoolkit/views/mixins/__init__.py,sha256=mHD49OUxuJ9v81tGfM0hLnUJuJlYi7E-5cTVdplh-vs,91
|
52
53
|
djresttoolkit/views/mixins/_retrieve_object_mixin.py,sha256=v7CQDUkRWjtevFZnAYRBdDl7wcfYWF3evWoKWHAcckA,1749
|
53
|
-
djresttoolkit-1.1.
|
54
|
-
djresttoolkit-1.1.
|
55
|
-
djresttoolkit-1.1.
|
56
|
-
djresttoolkit-1.1.
|
57
|
-
djresttoolkit-1.1.
|
54
|
+
djresttoolkit-1.2.1.dist-info/METADATA,sha256=tfUlUP1aTjciJVuxWBmGMr_pJngjAOKwihneOuThlUI,32697
|
55
|
+
djresttoolkit-1.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
56
|
+
djresttoolkit-1.2.1.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
|
57
|
+
djresttoolkit-1.2.1.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
|
58
|
+
djresttoolkit-1.2.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|