djresttoolkit 1.1.0__tar.gz → 1.2.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 (249) hide show
  1. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/PKG-INFO +22 -1
  2. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/README.md +21 -0
  3. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/models.py +20 -1
  4. djresttoolkit-1.2.0/demo/apps/todos/serializers.py +9 -0
  5. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/urls.py +2 -1
  6. djresttoolkit-1.2.0/demo/apps/todos/views.py +43 -0
  7. djresttoolkit-1.2.0/demo/apps_config/__init__.py +3 -0
  8. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/settings.py +3 -1
  9. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/pyproject.toml +13 -9
  10. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/pagination/_paginated_data_builder.py +6 -4
  11. djresttoolkit-1.2.0/src/djresttoolkit/serializers/__init__.py +3 -0
  12. djresttoolkit-1.2.0/src/djresttoolkit/serializers/_enhanced_model_serializer.py +59 -0
  13. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/uv.lock +1 -1
  14. djresttoolkit-1.1.0/demo/apps/todos/views.py +0 -18
  15. djresttoolkit-1.1.0/src/djresttoolkit/serializers/__init__.py +0 -0
  16. djresttoolkit-1.1.0/src/djresttoolkit/views/_apiviews/__init__.py +0 -0
  17. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/.gitignore +0 -0
  18. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/.python-version +0 -0
  19. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/.vscode/settings.json +0 -0
  20. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/LICENSE +0 -0
  21. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/__init__.py +0 -0
  22. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/admin.py +0 -0
  23. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/apps.py +0 -0
  24. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/dbseed/__init__.py +0 -0
  25. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/dbseed/tag_seed.py +0 -0
  26. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/dbseed/todo_seed.py +0 -0
  27. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/dbseed/todo_tag_seed.py +0 -0
  28. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/migrations/0001_initial.py +0 -0
  29. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/migrations/__init__.py +0 -0
  30. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps/todos/tests.py +0 -0
  31. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/asgi.py +0 -0
  32. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/serializers.py +0 -0
  33. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/urls.py +0 -0
  34. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/views.py +0 -0
  35. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/apps_config/wsgi.py +0 -0
  36. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/manage.py +0 -0
  37. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/autocomplete.css +0 -0
  38. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/base.css +0 -0
  39. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/changelists.css +0 -0
  40. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/dark_mode.css +0 -0
  41. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/dashboard.css +0 -0
  42. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/forms.css +0 -0
  43. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/login.css +0 -0
  44. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/nav_sidebar.css +0 -0
  45. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/responsive.css +0 -0
  46. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/responsive_rtl.css +0 -0
  47. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/rtl.css +0 -0
  48. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/unusable_password_field.css +0 -0
  49. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md +0 -0
  50. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/vendor/select2/select2.css +0 -0
  51. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/vendor/select2/select2.min.css +0 -0
  52. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/css/widgets.css +0 -0
  53. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/LICENSE +0 -0
  54. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/README.txt +0 -0
  55. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/calendar-icons.svg +0 -0
  56. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/gis/move_vertex_off.svg +0 -0
  57. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/gis/move_vertex_on.svg +0 -0
  58. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-addlink.svg +0 -0
  59. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-alert.svg +0 -0
  60. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-calendar.svg +0 -0
  61. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-changelink.svg +0 -0
  62. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-clock.svg +0 -0
  63. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-deletelink.svg +0 -0
  64. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-hidelink.svg +0 -0
  65. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-no.svg +0 -0
  66. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-unknown-alt.svg +0 -0
  67. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-unknown.svg +0 -0
  68. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-viewlink.svg +0 -0
  69. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/icon-yes.svg +0 -0
  70. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/inline-delete.svg +0 -0
  71. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/search.svg +0 -0
  72. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/selector-icons.svg +0 -0
  73. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/sorting-icons.svg +0 -0
  74. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/tooltag-add.svg +0 -0
  75. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/img/tooltag-arrowright.svg +0 -0
  76. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/SelectBox.js +0 -0
  77. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/SelectFilter2.js +0 -0
  78. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/actions.js +0 -0
  79. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/admin/DateTimeShortcuts.js +0 -0
  80. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/admin/RelatedObjectLookups.js +0 -0
  81. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/autocomplete.js +0 -0
  82. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/calendar.js +0 -0
  83. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/cancel.js +0 -0
  84. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/change_form.js +0 -0
  85. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/core.js +0 -0
  86. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/filters.js +0 -0
  87. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/inlines.js +0 -0
  88. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/jquery.init.js +0 -0
  89. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/nav_sidebar.js +0 -0
  90. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/popup_response.js +0 -0
  91. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/prepopulate.js +0 -0
  92. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/prepopulate_init.js +0 -0
  93. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/theme.js +0 -0
  94. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/unusable_password_field.js +0 -0
  95. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/urlify.js +0 -0
  96. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/jquery/LICENSE.txt +0 -0
  97. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/jquery/jquery.js +0 -0
  98. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/jquery/jquery.min.js +0 -0
  99. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/LICENSE.md +0 -0
  100. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/af.js +0 -0
  101. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ar.js +0 -0
  102. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/az.js +0 -0
  103. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/bg.js +0 -0
  104. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/bn.js +0 -0
  105. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/bs.js +0 -0
  106. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ca.js +0 -0
  107. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/cs.js +0 -0
  108. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/da.js +0 -0
  109. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/de.js +0 -0
  110. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/dsb.js +0 -0
  111. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/el.js +0 -0
  112. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/en.js +0 -0
  113. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/es.js +0 -0
  114. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/et.js +0 -0
  115. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/eu.js +0 -0
  116. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/fa.js +0 -0
  117. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/fi.js +0 -0
  118. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/fr.js +0 -0
  119. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/gl.js +0 -0
  120. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/he.js +0 -0
  121. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/hi.js +0 -0
  122. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/hr.js +0 -0
  123. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/hsb.js +0 -0
  124. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/hu.js +0 -0
  125. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/hy.js +0 -0
  126. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/id.js +0 -0
  127. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/is.js +0 -0
  128. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/it.js +0 -0
  129. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ja.js +0 -0
  130. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ka.js +0 -0
  131. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/km.js +0 -0
  132. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ko.js +0 -0
  133. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/lt.js +0 -0
  134. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/lv.js +0 -0
  135. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/mk.js +0 -0
  136. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ms.js +0 -0
  137. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/nb.js +0 -0
  138. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ne.js +0 -0
  139. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/nl.js +0 -0
  140. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/pl.js +0 -0
  141. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ps.js +0 -0
  142. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/pt-BR.js +0 -0
  143. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/pt.js +0 -0
  144. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ro.js +0 -0
  145. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/ru.js +0 -0
  146. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sk.js +0 -0
  147. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sl.js +0 -0
  148. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sq.js +0 -0
  149. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js +0 -0
  150. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sr.js +0 -0
  151. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/sv.js +0 -0
  152. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/th.js +0 -0
  153. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/tk.js +0 -0
  154. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/tr.js +0 -0
  155. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/uk.js +0 -0
  156. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/vi.js +0 -0
  157. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/zh-CN.js +0 -0
  158. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/i18n/zh-TW.js +0 -0
  159. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/select2.full.js +0 -0
  160. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/select2/select2.full.min.js +0 -0
  161. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/xregexp/LICENSE.txt +0 -0
  162. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/xregexp/xregexp.js +0 -0
  163. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/admin/js/vendor/xregexp/xregexp.min.js +0 -0
  164. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/bootstrap-theme.min.css +0 -0
  165. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/bootstrap-theme.min.css.map +0 -0
  166. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/bootstrap-tweaks.css +0 -0
  167. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/bootstrap.min.css +0 -0
  168. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/bootstrap.min.css.map +0 -0
  169. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/default.css +0 -0
  170. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/font-awesome-4.0.3.css +0 -0
  171. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/css/prettify.css +0 -0
  172. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/css/base.css +0 -0
  173. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/css/highlight.css +0 -0
  174. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/css/jquery.json-view.min.css +0 -0
  175. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/img/favicon.ico +0 -0
  176. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/img/grid.png +0 -0
  177. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/js/api.js +0 -0
  178. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/js/highlight.pack.js +0 -0
  179. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/docs/js/jquery.json-view.min.js +0 -0
  180. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/fontawesome-webfont.eot +0 -0
  181. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/fontawesome-webfont.svg +0 -0
  182. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/fontawesome-webfont.ttf +0 -0
  183. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/fontawesome-webfont.woff +0 -0
  184. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.eot +0 -0
  185. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.svg +0 -0
  186. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.ttf +0 -0
  187. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff +0 -0
  188. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/fonts/glyphicons-halflings-regular.woff2 +0 -0
  189. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/img/glyphicons-halflings-white.png +0 -0
  190. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/img/glyphicons-halflings.png +0 -0
  191. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/img/grid.png +0 -0
  192. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/ajax-form.js +0 -0
  193. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/bootstrap.min.js +0 -0
  194. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/coreapi-0.1.1.js +0 -0
  195. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/csrf.js +0 -0
  196. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/default.js +0 -0
  197. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/jquery-3.7.1.min.js +0 -0
  198. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/load-ajax-form.js +0 -0
  199. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/demo/staticfiles/rest_framework/js/prettify-min.js +0 -0
  200. {djresttoolkit-1.1.0/demo/apps_config → djresttoolkit-1.2.0/src/djresttoolkit}/__init__.py +0 -0
  201. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/admin.py +0 -0
  202. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/apps.py +0 -0
  203. {djresttoolkit-1.1.0/src/djresttoolkit → djresttoolkit-1.2.0/src/djresttoolkit/cache}/__init__.py +0 -0
  204. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/__init__.py +0 -0
  205. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/_cache_action_mixin.py +0 -0
  206. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/_cache_invalidate_mixin.py +0 -0
  207. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/_cache_key_mixin.py +0 -0
  208. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/_cache_list_retrieve_mixin.py +0 -0
  209. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/cache/mixins/_cache_ops_mixin.py +0 -0
  210. {djresttoolkit-1.1.0/src/djresttoolkit/cache → djresttoolkit-1.2.0/src/djresttoolkit/dbseed}/__init__.py +0 -0
  211. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/dbseed/models/__init__.py +0 -0
  212. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/dbseed/models/_choice_field.py +0 -0
  213. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/dbseed/models/_gen.py +0 -0
  214. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/dbseed/models/_seed_model.py +0 -0
  215. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/envconfig/__init__.py +0 -0
  216. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/envconfig/_base_env_config.py +0 -0
  217. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/mail/__init__.py +0 -0
  218. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/mail/_email_sender.py +0 -0
  219. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/mail/_models.py +0 -0
  220. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/mail/_types.py +0 -0
  221. {djresttoolkit-1.1.0/src/djresttoolkit/dbseed → djresttoolkit-1.2.0/src/djresttoolkit/management}/__init__.py +0 -0
  222. {djresttoolkit-1.1.0/src/djresttoolkit/management → djresttoolkit-1.2.0/src/djresttoolkit/management/commands}/__init__.py +0 -0
  223. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/management/commands/dbflush.py +0 -0
  224. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/management/commands/dbseed.py +0 -0
  225. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/middlewares/__init__.py +0 -0
  226. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/middlewares/_response_time_middleware.py +0 -0
  227. {djresttoolkit-1.1.0/src/djresttoolkit/management/commands → djresttoolkit-1.2.0/src/djresttoolkit/migrations}/__init__.py +0 -0
  228. {djresttoolkit-1.1.0/src/djresttoolkit/migrations → djresttoolkit-1.2.0/src/djresttoolkit/models}/__init__.py +0 -0
  229. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/models/mixins/__init__.py +0 -0
  230. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/models/mixins/_model_choice_fields_mixin.py +0 -0
  231. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/pagination/__init__.py +0 -0
  232. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/pagination/_page_number_pagination.py +0 -0
  233. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/py.typed +0 -0
  234. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/renderers/__init__.py +0 -0
  235. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/renderers/_throttle_info_json_renderer.py +0 -0
  236. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/serializers/mixins/__init__.py +0 -0
  237. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/serializers/mixins/_absolute_url_file_mixin.py +0 -0
  238. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/serializers/mixins/_bulk_create_mixin.py +0 -0
  239. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/throttling/__init__.py +0 -0
  240. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/throttling/_throttle_inspector.py +0 -0
  241. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/urls/__init__.py +0 -0
  242. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/urls/_build_absolute_uri.py +0 -0
  243. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/views/__init__.py +0 -0
  244. {djresttoolkit-1.1.0/src/djresttoolkit/models → djresttoolkit-1.2.0/src/djresttoolkit/views/_apiviews}/__init__.py +0 -0
  245. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/views/_apiviews/_choice_fields_apiview.py +0 -0
  246. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/views/_exceptions/__init__.py +0 -0
  247. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/views/_exceptions/_exception_handler.py +0 -0
  248. {djresttoolkit-1.1.0 → djresttoolkit-1.2.0}/src/djresttoolkit/views/mixins/__init__.py +0 -0
  249. {djresttoolkit-1.1.0 → djresttoolkit-1.2.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: 1.1.0
3
+ Version: 1.2.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
@@ -1081,6 +1081,27 @@ class BookViewSet(CacheInvalidateMixin, ModelViewSet):
1081
1081
  - Invalidates caches when books are created, updated, or deleted.
1082
1082
  - Supports custom cache keys per action.
1083
1083
 
1084
+ ### 17. EnhancedModelSerializer — API Reference
1085
+
1086
+ A subclass of Django REST Framework’s `ModelSerializer` that automatically merges Django model field `error_messages` into the serializer field, unless explicitly overridden.
1087
+ This helps maintain consistent validation messages between the model and the serializer.
1088
+
1089
+ #### Type Parameters
1090
+
1091
+ - `T` (`Model`): The Django model type that the serializer corresponds to.
1092
+
1093
+ #### Example of EnhancedModelSerializer
1094
+
1095
+ ```python
1096
+ from myapp.models import Book
1097
+ from myapp.serializers import EnhancedModelSerializer
1098
+
1099
+ class BookSerializer(EnhancedModelSerializer[Book]):
1100
+ class Meta:
1101
+ model = Book
1102
+ fields = "__all__"
1103
+ ```
1104
+
1084
1105
  ## 🛠️ Planned Features
1085
1106
 
1086
1107
  - Add more utils
@@ -1025,6 +1025,27 @@ class BookViewSet(CacheInvalidateMixin, ModelViewSet):
1025
1025
  - Invalidates caches when books are created, updated, or deleted.
1026
1026
  - Supports custom cache keys per action.
1027
1027
 
1028
+ ### 17. EnhancedModelSerializer — API Reference
1029
+
1030
+ A subclass of Django REST Framework’s `ModelSerializer` that automatically merges Django model field `error_messages` into the serializer field, unless explicitly overridden.
1031
+ This helps maintain consistent validation messages between the model and the serializer.
1032
+
1033
+ #### Type Parameters
1034
+
1035
+ - `T` (`Model`): The Django model type that the serializer corresponds to.
1036
+
1037
+ #### Example of EnhancedModelSerializer
1038
+
1039
+ ```python
1040
+ from myapp.models import Book
1041
+ from myapp.serializers import EnhancedModelSerializer
1042
+
1043
+ class BookSerializer(EnhancedModelSerializer[Book]):
1044
+ class Meta:
1045
+ model = Book
1046
+ fields = "__all__"
1047
+ ```
1048
+
1028
1049
  ## 🛠️ Planned Features
1029
1050
 
1030
1051
  - Add more utils
@@ -57,8 +57,18 @@ class Todo(BaseModel):
57
57
  on_delete=CASCADE,
58
58
  related_name="todos",
59
59
  help_text="Owner of this todo",
60
+ error_messages={
61
+ "null": "Every todo must belong to a user.",
62
+ "invalid": "Invalid user reference.",
63
+ },
64
+ )
65
+ title: CharField[str, str] = CharField(
66
+ max_length=255,
67
+ error_messages={
68
+ "blank": "Please give your todo a title.",
69
+ "max_length": "The title cannot exceed 255 characters.",
70
+ },
60
71
  )
61
- title: CharField[str, str] = CharField(max_length=255)
62
72
  description: TextField[str, str] = TextField(blank=True, default="")
63
73
  due_date: DateTimeField[str | None, str | None] = DateTimeField(
64
74
  null=True,
@@ -69,16 +79,25 @@ class Todo(BaseModel):
69
79
  max_length=20,
70
80
  choices=TodoPriority.choices,
71
81
  default=TodoPriority.MEDIUM,
82
+ error_messages={
83
+ "invalid_choice": "Priority must be one of: low, medium, high, critical.",
84
+ },
72
85
  )
73
86
  status: CharField[str, str] = CharField(
74
87
  max_length=20,
75
88
  choices=TodoStatus.choices,
76
89
  default=TodoStatus.PENDING,
90
+ error_messages={
91
+ "invalid_choice": "Status must be one of: pending, in_progress, completed, archived.",
92
+ },
77
93
  )
78
94
 
79
95
  completed_at: DateTimeField[str | None, str | None] = DateTimeField(
80
96
  null=True,
81
97
  blank=True,
98
+ error_messages={
99
+ "invalid": "Completed at must be a valid datetime.",
100
+ },
82
101
  )
83
102
 
84
103
  def mark_completed(self) -> None:
@@ -0,0 +1,9 @@
1
+ from djresttoolkit.serializers import EnhancedModelSerializer
2
+
3
+ from .models import Todo
4
+
5
+
6
+ class TodoSerializer(EnhancedModelSerializer[Todo]):
7
+ class Meta:
8
+ model = Todo
9
+ exclude = ["created_at", "updated_at"]
@@ -4,8 +4,9 @@ URL configuration for todos app.
4
4
 
5
5
  from django.urls import path
6
6
 
7
- from .views import TodoDetailView
7
+ from .views import TodoDetailView, TodoListView
8
8
 
9
9
  urlpatterns = [
10
+ path("", TodoListView.as_view(), name="todo-list"),
10
11
  path("<int:id>/", TodoDetailView.as_view(), name="todo-detail"),
11
12
  ]
@@ -0,0 +1,43 @@
1
+ from rest_framework.permissions import AllowAny
2
+ from rest_framework.request import Request
3
+ from rest_framework.response import Response
4
+ from rest_framework.views import APIView
5
+
6
+ from djresttoolkit.pagination import PaginatedDataBuilder
7
+ from djresttoolkit.views.mixins import RetrieveObjectMixin
8
+
9
+ from .models import Todo
10
+ from .serializers import TodoSerializer
11
+
12
+
13
+ class TodoListView(APIView):
14
+ permission_classes = [AllowAny]
15
+
16
+ def get(self, request: Request) -> Response:
17
+ pagination = PaginatedDataBuilder[Todo](
18
+ request=request,
19
+ serializer_class=TodoSerializer,
20
+ queryset=Todo.objects.all(),
21
+ )
22
+ return Response(data=pagination.get_paginated_data())
23
+
24
+ def post(self, request: Request) -> Response:
25
+ serializer = TodoSerializer(
26
+ data=request.data,
27
+ many=isinstance(request.data, list),
28
+ )
29
+
30
+ if serializer.is_valid():
31
+ serializer.save(user=request.user)
32
+
33
+ return Response(data=serializer.data)
34
+
35
+
36
+ class TodoDetailView(RetrieveObjectMixin[Todo], APIView):
37
+ permission_classes = [AllowAny]
38
+ queryset = Todo.objects.all()
39
+
40
+ def get(self, request: Request, id: int) -> Response:
41
+ todo = self.get_object(id=id)
42
+ serializer = TodoSerializer(instance=todo, many=False)
43
+ return Response(data=serializer.data)
@@ -0,0 +1,3 @@
1
+ from dotenv import load_dotenv
2
+
3
+ load_dotenv()
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ from os import getenv
2
3
  from pathlib import Path
3
4
 
4
5
  # Configuration Settings File for the django backend
@@ -12,7 +13,7 @@ sys.path.insert(0, str(SRC_DIR))
12
13
 
13
14
  # Security Configuration Settings
14
15
  # -------------------------------
15
- SECRET_KEY = "asdkjasdjgasdgjioarejalk54884a651asdgklnaskdg"
16
+ SECRET_KEY = getenv("SECRET_KEY")
16
17
 
17
18
  # DEBUG Configuration Settings
18
19
  # ----------------------------
@@ -164,6 +165,7 @@ MEDIA_URL = "/media/"
164
165
  # -------------------------------------
165
166
  REST_FRAMEWORK = {
166
167
  "NON_FIELD_ERRORS_KEY": "non_field",
168
+ "DATETIME_FORMAT": "%Y-%m-%d %H:%M",
167
169
  "DEFAULT_AUTHENTICATION_CLASSES": [
168
170
  "rest_framework.authentication.TokenAuthentication",
169
171
  ],
@@ -4,7 +4,7 @@
4
4
 
5
5
  [project]
6
6
  name = "djresttoolkit"
7
- version = "1.1.0"
7
+ version = "1.2.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" }
@@ -45,10 +45,7 @@ keywords = [
45
45
  "python-package",
46
46
  ]
47
47
  requires-python = ">=3.13"
48
- dependencies = [
49
- "faker>=37.5.3",
50
- "pydantic>=2.11.7",
51
- ]
48
+ dependencies = ["faker>=37.5.3", "pydantic>=2.11.7"]
52
49
 
53
50
  # CLI scripts entry point configuration
54
51
  # -------------------------------------
@@ -109,12 +106,19 @@ Source = "https://github.com/shaileshpandit141/djresttoolkit"
109
106
  Issues = "https://github.com/shaileshpandit141/djresttoolkit/issues"
110
107
  License = "https://github.com/shaileshpandit141/djresttoolkit/blob/main/LICENSE"
111
108
 
112
- # ===================
113
- # Tool Configurations
114
- # ===================
115
109
 
110
+ # ==========================
111
+ # Add pyright Configurations
112
+ # ==========================
113
+ [tool.pyright]
114
+ typeCheckingMode = "strict"
115
+ reportMissingTypeStubs = false
116
+ reportUnknownMemberType = false
117
+ reportIncompatibleVariableOverride = false
118
+
119
+ # =========================================
116
120
  # Disable ruff S101 rule for test casecases
117
- # -----------------------------------------
121
+ # =========================================
118
122
  [tool.ruff.lint.per-file-ignores]
119
123
  "tests/*.py" = ["S101"]
120
124
 
@@ -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
- from django.db.models import Model
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
@@ -0,0 +1,3 @@
1
+ from ._enhanced_model_serializer import EnhancedModelSerializer
2
+
3
+ __all__ = ["EnhancedModelSerializer"]
@@ -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
+ )
@@ -342,7 +342,7 @@ wheels = [
342
342
 
343
343
  [[package]]
344
344
  name = "djresttoolkit"
345
- version = "1.0.0"
345
+ version = "1.1.0"
346
346
  source = { editable = "." }
347
347
  dependencies = [
348
348
  { name = "faker" },
@@ -1,18 +0,0 @@
1
- from django.forms.models import model_to_dict
2
- from rest_framework.permissions import AllowAny
3
- from rest_framework.request import Request
4
- from rest_framework.response import Response
5
- from rest_framework.views import APIView
6
-
7
- from djresttoolkit.views.mixins import RetrieveObjectMixin
8
-
9
- from .models import Todo
10
-
11
-
12
- class TodoDetailView(RetrieveObjectMixin[Todo], APIView):
13
- permission_classes = [AllowAny]
14
- queryset = Todo.objects.all()
15
-
16
- def get(self, request: Request, id: int) -> Response:
17
- todo = self.get_object(id=id)
18
- return Response(data=model_to_dict(todo))
File without changes
File without changes