djresttoolkit 0.13.0__tar.gz → 0.15.0__tar.gz

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.
Files changed (50) hide show
  1. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/PKG-INFO +118 -1
  2. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/README.md +117 -0
  3. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/pyproject.toml +1 -1
  4. djresttoolkit-0.15.0/src/djresttoolkit/pagination/__init__.py +3 -0
  5. djresttoolkit-0.15.0/src/djresttoolkit/pagination/_page_number_pagination.py +69 -0
  6. djresttoolkit-0.15.0/src/djresttoolkit/urls/__init__.py +3 -0
  7. djresttoolkit-0.15.0/src/djresttoolkit/urls/_build_absolute_uri.py +33 -0
  8. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/.gitignore +0 -0
  9. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/LICENSE +0 -0
  10. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/demo/staticfiles/admin/img/LICENSE +0 -0
  11. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/__init__.py +0 -0
  12. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/admin.py +0 -0
  13. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/apps.py +0 -0
  14. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/dbseed/__init__.py +0 -0
  15. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/dbseed/models/__init__.py +0 -0
  16. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/dbseed/models/_choice_field.py +0 -0
  17. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/dbseed/models/_gen.py +0 -0
  18. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/dbseed/models/_seed_model.py +0 -0
  19. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/envconfig/__init__.py +0 -0
  20. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/envconfig/_env_settings.py +0 -0
  21. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/mail/__init__.py +0 -0
  22. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/mail/_email_sender.py +0 -0
  23. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/mail/_models.py +0 -0
  24. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/mail/_types.py +0 -0
  25. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/management/__init__.py +0 -0
  26. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/management/commands/__init__.py +0 -0
  27. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/management/commands/dbflush.py +0 -0
  28. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/management/commands/dbseed.py +0 -0
  29. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/middlewares/__init__.py +0 -0
  30. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/middlewares/_response_time_middleware.py +0 -0
  31. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/migrations/__init__.py +0 -0
  32. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/models/__init__.py +0 -0
  33. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/models/mixins/__init__.py +0 -0
  34. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/models/mixins/_model_choice_fields_mixin.py +0 -0
  35. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/py.typed +0 -0
  36. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/renderers/__init__.py +0 -0
  37. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/renderers/_throttle_info_json_renderer.py +0 -0
  38. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/serializers/__init__.py +0 -0
  39. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/serializers/mixins/__init__.py +0 -0
  40. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/serializers/mixins/_absolute_url_file_mixin.py +0 -0
  41. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/serializers/mixins/_bulk_create_mixin.py +0 -0
  42. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/throttling/__init__.py +0 -0
  43. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/throttling/_throttle_inspector.py +0 -0
  44. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/__init__.py +0 -0
  45. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/_api_views/__init__.py +0 -0
  46. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/_api_views/_choice_fields_apiview.py +0 -0
  47. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/_exceptions/__init__.py +0 -0
  48. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/_exceptions/_exception_handler.py +0 -0
  49. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/mixins/__init__.py +0 -0
  50. {djresttoolkit-0.13.0 → djresttoolkit-0.15.0}/src/djresttoolkit/views/mixins/_retrieve_object_mixin.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djresttoolkit
3
- Version: 0.13.0
3
+ Version: 0.15.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
@@ -807,6 +807,123 @@ class BookDetailView(RetrieveObjectMixin[Book], APIView):
807
807
  - Returns `None` instead of raising `DoesNotExist`, making error handling easier.
808
808
  - Works with any Django model and queryset.
809
809
 
810
+ ### 13. build_absolute_uri — API Reference
811
+
812
+ ```python
813
+ from djresttoolkit.urls import build_absolute_uri
814
+ ```
815
+
816
+ #### build absolute uri Description
817
+
818
+ - Builds a **fully qualified absolute URL** for a Django or DRF view.
819
+ - Optionally includes **query parameters**.
820
+ - Works with both **Django `HttpRequest`** and **DRF `Request`** objects.
821
+ - Uses Django's `reverse()` to dynamically resolve URL names.
822
+
823
+ #### build absolute uri Function Signature
824
+
825
+ ```python
826
+ def build_absolute_uri(
827
+ request: HttpRequest | Request,
828
+ url_name: str,
829
+ query_params: dict[str, Any] | None = None,
830
+ *args: Any,
831
+ **kwargs: Any,
832
+ ) -> str:
833
+ ...
834
+ ```
835
+
836
+ ---
837
+
838
+ #### build absolute uri Parameters
839
+
840
+ - `request` (`HttpRequest | Request`): The incoming Django or DRF request object.
841
+ - `url_name` (`str`): Name of the URL pattern to reverse.
842
+ - `query_params` (`dict[str, Any] | None`): Optional dictionary of query parameters to append to the URL.
843
+ - `*args` (`Any`): Positional arguments for the URL reversal.
844
+ - `**kwargs` (`Any`): Keyword arguments for the URL reversal.
845
+
846
+ ---
847
+
848
+ ### build absolute uri Returns
849
+
850
+ - `str`: Absolute URI of the view including optional query parameters.
851
+
852
+ ### Example of build absolute uri
853
+
854
+ ```python
855
+ from django.http import HttpRequest
856
+ from djresttoolkit.utils import build_absolute_uri
857
+
858
+ def my_view(request: HttpRequest):
859
+ absolute_url = build_absolute_uri(
860
+ request,
861
+ url_name="book-detail",
862
+ query_params={"ref": "newsletter"},
863
+ pk=123
864
+ )
865
+ return HttpResponse(f"URL: {absolute_url}")
866
+ ```
867
+
868
+ **Output Example:**
869
+
870
+ ```url
871
+ https://example.com/api/books/123/?ref=newsletter
872
+ ```
873
+
874
+ ### 14. PageNumberPagination — API Reference
875
+
876
+ ```python
877
+ from djresttoolkit.pagination import PageNumberPagination
878
+ ```
879
+
880
+ #### Description of Page Number Pagination
881
+
882
+ - Extends **DRF’s `PageNumberPagination`** with a **cleaner metadata structure**.
883
+ - Adds support for **dynamic page size** via the `page-size` query parameter.
884
+ - Returns pagination metadata inside a `"page"` object, separate from `"results"`.
885
+
886
+ #### Features of Page Number Pagination
887
+
888
+ - Clients can control items per page using `?page-size=`.
889
+ - Structured pagination metadata:
890
+
891
+ - `current` → current page number
892
+ - `total` → total number of pages
893
+ - `size` → number of items per page
894
+ - `total_items` → total number of items across all pages
895
+ - `next` → next page URL
896
+ - `previous` → previous page URL
897
+ - Standardized API response format.
898
+
899
+ ### Attributes of Page Number Pagination
900
+
901
+ - `page_size_query_param: str` → Query parameter name (`"page-size"`).
902
+
903
+ ### Page Number Pagination Methods
904
+
905
+ - `get_paginated_response(data: Any) -> Response`
906
+ Returns a JSON response with both pagination metadata and results.
907
+
908
+ ### Example Response of Page Number Pagination
909
+
910
+ ```json
911
+ {
912
+ "page": {
913
+ "current": 1,
914
+ "total": 10,
915
+ "size": 20,
916
+ "total_items": 200,
917
+ "next": "http://api.example.com/items/?page=2&page-size=20",
918
+ "previous": null
919
+ },
920
+ "results": [
921
+ { "id": 1, "name": "Item 1" },
922
+ { "id": 2, "name": "Item 2" }
923
+ ]
924
+ }
925
+ ```
926
+
810
927
  ## 🛠️ Planned Features
811
928
 
812
929
  - Add more utils
@@ -749,6 +749,123 @@ class BookDetailView(RetrieveObjectMixin[Book], APIView):
749
749
  - Returns `None` instead of raising `DoesNotExist`, making error handling easier.
750
750
  - Works with any Django model and queryset.
751
751
 
752
+ ### 13. build_absolute_uri — API Reference
753
+
754
+ ```python
755
+ from djresttoolkit.urls import build_absolute_uri
756
+ ```
757
+
758
+ #### build absolute uri Description
759
+
760
+ - Builds a **fully qualified absolute URL** for a Django or DRF view.
761
+ - Optionally includes **query parameters**.
762
+ - Works with both **Django `HttpRequest`** and **DRF `Request`** objects.
763
+ - Uses Django's `reverse()` to dynamically resolve URL names.
764
+
765
+ #### build absolute uri Function Signature
766
+
767
+ ```python
768
+ def build_absolute_uri(
769
+ request: HttpRequest | Request,
770
+ url_name: str,
771
+ query_params: dict[str, Any] | None = None,
772
+ *args: Any,
773
+ **kwargs: Any,
774
+ ) -> str:
775
+ ...
776
+ ```
777
+
778
+ ---
779
+
780
+ #### build absolute uri Parameters
781
+
782
+ - `request` (`HttpRequest | Request`): The incoming Django or DRF request object.
783
+ - `url_name` (`str`): Name of the URL pattern to reverse.
784
+ - `query_params` (`dict[str, Any] | None`): Optional dictionary of query parameters to append to the URL.
785
+ - `*args` (`Any`): Positional arguments for the URL reversal.
786
+ - `**kwargs` (`Any`): Keyword arguments for the URL reversal.
787
+
788
+ ---
789
+
790
+ ### build absolute uri Returns
791
+
792
+ - `str`: Absolute URI of the view including optional query parameters.
793
+
794
+ ### Example of build absolute uri
795
+
796
+ ```python
797
+ from django.http import HttpRequest
798
+ from djresttoolkit.utils import build_absolute_uri
799
+
800
+ def my_view(request: HttpRequest):
801
+ absolute_url = build_absolute_uri(
802
+ request,
803
+ url_name="book-detail",
804
+ query_params={"ref": "newsletter"},
805
+ pk=123
806
+ )
807
+ return HttpResponse(f"URL: {absolute_url}")
808
+ ```
809
+
810
+ **Output Example:**
811
+
812
+ ```url
813
+ https://example.com/api/books/123/?ref=newsletter
814
+ ```
815
+
816
+ ### 14. PageNumberPagination — API Reference
817
+
818
+ ```python
819
+ from djresttoolkit.pagination import PageNumberPagination
820
+ ```
821
+
822
+ #### Description of Page Number Pagination
823
+
824
+ - Extends **DRF’s `PageNumberPagination`** with a **cleaner metadata structure**.
825
+ - Adds support for **dynamic page size** via the `page-size` query parameter.
826
+ - Returns pagination metadata inside a `"page"` object, separate from `"results"`.
827
+
828
+ #### Features of Page Number Pagination
829
+
830
+ - Clients can control items per page using `?page-size=`.
831
+ - Structured pagination metadata:
832
+
833
+ - `current` → current page number
834
+ - `total` → total number of pages
835
+ - `size` → number of items per page
836
+ - `total_items` → total number of items across all pages
837
+ - `next` → next page URL
838
+ - `previous` → previous page URL
839
+ - Standardized API response format.
840
+
841
+ ### Attributes of Page Number Pagination
842
+
843
+ - `page_size_query_param: str` → Query parameter name (`"page-size"`).
844
+
845
+ ### Page Number Pagination Methods
846
+
847
+ - `get_paginated_response(data: Any) -> Response`
848
+ Returns a JSON response with both pagination metadata and results.
849
+
850
+ ### Example Response of Page Number Pagination
851
+
852
+ ```json
853
+ {
854
+ "page": {
855
+ "current": 1,
856
+ "total": 10,
857
+ "size": 20,
858
+ "total_items": 200,
859
+ "next": "http://api.example.com/items/?page=2&page-size=20",
860
+ "previous": null
861
+ },
862
+ "results": [
863
+ { "id": 1, "name": "Item 1" },
864
+ { "id": 2, "name": "Item 2" }
865
+ ]
866
+ }
867
+ ```
868
+
752
869
  ## 🛠️ Planned Features
753
870
 
754
871
  - Add more utils
@@ -4,7 +4,7 @@
4
4
 
5
5
  [project]
6
6
  name = "djresttoolkit"
7
- version = "0.13.0"
7
+ version = "0.15.0"
8
8
  description = "A collection of Django and DRF utilities to simplify API development."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = { file = "LICENSE" }
@@ -0,0 +1,3 @@
1
+ from ._page_number_pagination import PageNumberPagination
2
+
3
+ __all__ = ["PageNumberPagination"]
@@ -0,0 +1,69 @@
1
+ from typing import Any
2
+
3
+ from rest_framework.exceptions import ValidationError
4
+ from rest_framework.pagination import PageNumberPagination as DrfPageNumberPagination
5
+ from rest_framework.response import Response
6
+
7
+
8
+ class PageNumberPagination(DrfPageNumberPagination):
9
+ """
10
+ Custom PageNumberPagination for Django REST Framework.
11
+
12
+ This pagination class extends DRF's PageNumberPagination to provide:
13
+ - Dynamic page size support via the "page-size" query parameter.
14
+ - A streamlined, structured pagination metadata format in API responses.
15
+
16
+ Features:
17
+ - Clients can control the number of items per page using the "page-size" query parameter.
18
+ - The paginated response includes a "page" object with detailed pagination metadata and a "results" list.
19
+
20
+ Paginated Response Example:
21
+ ```
22
+ {
23
+ "page": {
24
+ "current": 1,
25
+ "total": 10,
26
+ "size": 20,
27
+ "total_items": 200,
28
+ "next": "http://api.example.com/items/?page=2&page-size=20",
29
+ "previous": null
30
+ },
31
+ "results": [ ... ]
32
+ }
33
+ ```
34
+
35
+ Attributes:
36
+ page_size_query_param (str): Query parameter name for dynamic page size ("page-size").
37
+
38
+ Methods:
39
+ get_paginated_response(data: Any) -> Response:
40
+ Returns a standardized paginated response with metadata and results.
41
+
42
+ """
43
+
44
+ # Allow clients to set page size via ?page-size=
45
+ page_size_query_param = "page-size"
46
+
47
+ def get_paginated_response(self, data: Any) -> Response:
48
+ page = getattr(self, "page", None)
49
+ paginator = getattr(self, "paginator", None)
50
+ request = getattr(self, "request", None)
51
+ if page is None or paginator is None or request is None:
52
+ raise ValidationError(
53
+ {"detail": "Pagination has not been properly configured."}
54
+ )
55
+
56
+ items_per_page = self.get_page_size(request)
57
+ return Response(
58
+ {
59
+ "page": {
60
+ "current": page.number,
61
+ "total": paginator.num_pages,
62
+ "size": items_per_page,
63
+ "total_items": paginator.count,
64
+ "next": self.get_next_link(),
65
+ "previous": self.get_previous_link(),
66
+ },
67
+ "results": data,
68
+ }
69
+ )
@@ -0,0 +1,3 @@
1
+ from ._build_absolute_uri import build_absolute_uri
2
+
3
+ __all__ = ["build_absolute_uri"]
@@ -0,0 +1,33 @@
1
+ from typing import Any
2
+ from urllib.parse import urlencode
3
+ from django.http import HttpRequest
4
+ from django.urls import reverse
5
+ from rest_framework.request import Request
6
+
7
+
8
+ def build_absolute_uri(
9
+ request: HttpRequest | Request,
10
+ url_name: str,
11
+ query_params: dict[str, Any] | None = None,
12
+ *args: Any,
13
+ **kwargs: Any,
14
+ ) -> str:
15
+ """
16
+ Build an absolute URI for a given Django or DRF view.
17
+
18
+ Args:
19
+ request: Django or DRF request object.
20
+ url_name: Name of the URL pattern to reverse.
21
+ query_params: Optional dictionary of query parameters.
22
+ *args: Positional arguments for the URL.
23
+ **kwargs: Keyword arguments for the URL.
24
+
25
+ Returns:
26
+ Absolute URI as a string.
27
+ """
28
+ url = reverse(url_name, args=args, kwargs=kwargs)
29
+
30
+ if query_params:
31
+ url += f"?{urlencode(query_params, doseq=True)}"
32
+
33
+ return request.build_absolute_uri(url)
File without changes