django-ninja-aio-crud 2.3.0__tar.gz → 2.3.2__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 (104) hide show
  1. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.github/workflows/docs.yml +2 -0
  2. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/PKG-INFO +20 -11
  3. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/README.md +17 -8
  4. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/views/decorators.md +1 -2
  5. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/index.md +34 -43
  6. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/__init__.py +1 -1
  7. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/renders.py +2 -1
  8. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/pyproject.toml +2 -2
  9. django_ninja_aio_crud-2.3.0/examples/ex_1/models.py +0 -35
  10. django_ninja_aio_crud-2.3.0/examples/ex_1/urls.py +0 -11
  11. django_ninja_aio_crud-2.3.0/examples/ex_1/views.py +0 -16
  12. django_ninja_aio_crud-2.3.0/examples/ex_2/auth.py +0 -33
  13. django_ninja_aio_crud-2.3.0/examples/ex_2/models.py +0 -62
  14. django_ninja_aio_crud-2.3.0/examples/ex_2/urls.py +0 -11
  15. django_ninja_aio_crud-2.3.0/examples/ex_2/views.py +0 -26
  16. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.github/dependabot.yml +0 -0
  17. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.github/workflows/coverage.yml +0 -0
  18. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.github/workflows/publish.yml +0 -0
  19. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.gitignore +0 -0
  20. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/.pre-commit-config.yaml +0 -0
  21. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/LICENSE +0 -0
  22. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/CNAME +0 -0
  23. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/authentication.md +0 -0
  24. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/models/model_serializer.md +0 -0
  25. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/models/model_util.md +0 -0
  26. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/pagination.md +0 -0
  27. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/renderers/orjson_renderer.md +0 -0
  28. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/views/api_view.md +0 -0
  29. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/views/api_view_set.md +0 -0
  30. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/api/views/mixins.md +0 -0
  31. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/auth.md +0 -0
  32. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/contributing.md +0 -0
  33. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/extra.css +0 -0
  34. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-create-swagger.png +0 -0
  35. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-delete-swagger.png +0 -0
  36. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-list-swagger.png +0 -0
  37. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-retrieve-swagger.png +0 -0
  38. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-swagger.png +0 -0
  39. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/images/index/foo-index-update-swagger.png +0 -0
  40. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/installation.md +0 -0
  41. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/getting_started/quick_start.md +0 -0
  42. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/images/bar-swagger.png +0 -0
  43. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/images/favicon.ico +0 -0
  44. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/images/foo-swagger.png +0 -0
  45. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/images/logo.png +0 -0
  46. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/images/model_util/foo-reverse-relations-swagger.png +0 -0
  47. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/release_notes.md +0 -0
  48. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/requirements.txt +0 -0
  49. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/tutorial/authentication.md +0 -0
  50. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/tutorial/crud.md +0 -0
  51. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/tutorial/filtering.md +0 -0
  52. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/docs/tutorial/model.md +0 -0
  53. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/main.py +0 -0
  54. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/mkdocs.yml +0 -0
  55. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/api.py +0 -0
  56. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/auth.py +0 -0
  57. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/decorators/__init__.py +0 -0
  58. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/decorators/operations.py +0 -0
  59. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/decorators/views.py +0 -0
  60. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/exceptions.py +0 -0
  61. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/factory/__init__.py +0 -0
  62. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/factory/operations.py +0 -0
  63. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/helpers/__init__.py +0 -0
  64. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/helpers/api.py +0 -0
  65. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/helpers/query.py +0 -0
  66. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/models.py +0 -0
  67. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/parsers.py +0 -0
  68. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/schemas/__init__.py +0 -0
  69. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/schemas/api.py +0 -0
  70. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/schemas/generics.py +0 -0
  71. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/schemas/helpers.py +0 -0
  72. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/types.py +0 -0
  73. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/views/__init__.py +0 -0
  74. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/views/api.py +0 -0
  75. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/ninja_aio/views/mixins.py +0 -0
  76. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/requirements.dev.txt +0 -0
  77. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/run-local-coverage.sh +0 -0
  78. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/__init__.py +0 -0
  79. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/core/__init__.py +0 -0
  80. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/core/test_decorators.py +0 -0
  81. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/core/test_exceptions_api.py +0 -0
  82. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/core/test_renderer_parser.py +0 -0
  83. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/generics/__init__.py +0 -0
  84. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/generics/literals.py +0 -0
  85. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/generics/models.py +0 -0
  86. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/generics/request.py +0 -0
  87. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/generics/views.py +0 -0
  88. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/helpers/__init__.py +0 -0
  89. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/helpers/test_many_to_many_api.py +0 -0
  90. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/models/__init__.py +0 -0
  91. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/models/test_model_util.py +0 -0
  92. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/models/test_models_extra.py +0 -0
  93. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_app/__init__.py +0 -0
  94. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_app/models.py +0 -0
  95. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_app/schema.py +0 -0
  96. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_app/views.py +0 -0
  97. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_auth.py +0 -0
  98. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_decorators.py +0 -0
  99. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_exceptions.py +0 -0
  100. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_query_util.py +0 -0
  101. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/test_settings.py +0 -0
  102. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/views/__init__.py +0 -0
  103. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/views/test_views.py +0 -0
  104. {django_ninja_aio_crud-2.3.0 → django_ninja_aio_crud-2.3.2}/tests/views/test_viewset.py +0 -0
@@ -14,6 +14,7 @@ on:
14
14
  - "1.0"
15
15
  - "2.0"
16
16
  - "2.2"
17
+ - "2.3"
17
18
  make_latest:
18
19
  description: 'Set as "latest" and default?'
19
20
  type: boolean
@@ -31,6 +32,7 @@ on:
31
32
  - "1.0"
32
33
  - "2.0"
33
34
  - "2.2"
35
+ - "2.3"
34
36
  delete_confirm:
35
37
  description: 'Confirm deletion of the selected version'
36
38
  type: boolean
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-ninja-aio-crud
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: Django Ninja AIO CRUD - Rest Framework
5
5
  Author: Giuseppe Casillo
6
- Requires-Python: >=3.10, <=3.14
6
+ Requires-Python: >=3.10, <3.15
7
7
  Description-Content-Type: text/markdown
8
8
  Classifier: Operating System :: OS Independent
9
9
  Classifier: Topic :: Internet
@@ -25,7 +25,7 @@ Classifier: Framework :: AsyncIO
25
25
  Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
26
26
  Classifier: Topic :: Internet :: WWW/HTTP
27
27
  License-File: LICENSE
28
- Requires-Dist: django-ninja >=1.3.0, <=1.5.1
28
+ Requires-Dist: django-ninja >=1.3.0, <1.6
29
29
  Requires-Dist: joserfc >=1.0.0, <= 1.4.1
30
30
  Requires-Dist: orjson >= 3.10.7, <= 3.11.5
31
31
  Requires-Dist: coverage ; extra == "test"
@@ -74,6 +74,7 @@ Add to your project’s dependencies and ensure Django Ninja is installed.
74
74
  ## 🚀 Quick Start
75
75
 
76
76
  models.py
77
+
77
78
  ```python
78
79
  from django.db import models
79
80
  from ninja_aio.models import ModelSerializer
@@ -93,6 +94,7 @@ class Book(ModelSerializer):
93
94
  ```
94
95
 
95
96
  views.py
97
+
96
98
  ```python
97
99
  from ninja_aio import NinjaAIO
98
100
  from ninja_aio.views import APIViewSet
@@ -126,6 +128,7 @@ class BookViewSet(APIViewSet):
126
128
  ```
127
129
 
128
130
  Request:
131
+
129
132
  ```
130
133
  GET /book/?published=true&title=python
131
134
  ```
@@ -168,6 +171,7 @@ class ArticleViewSet(APIViewSet):
168
171
  ```
169
172
 
170
173
  Endpoints:
174
+
171
175
  - `GET /article/{pk}/tag?name=dev`
172
176
  - `POST /article/{pk}/tag/` body: `{"add":[1,2],"remove":[3]}`
173
177
 
@@ -202,6 +206,7 @@ class SecureBookViewSet(APIViewSet):
202
206
  ## 📑 Lifecycle Hooks (ModelSerializer)
203
207
 
204
208
  Available on every save/delete:
209
+
205
210
  - `on_create_before_save`
206
211
  - `on_create_after_save`
207
212
  - `before_save`
@@ -250,9 +255,8 @@ class LargePagination(PageNumberPagination):
250
255
  page_size = 50
251
256
  max_page_size = 200
252
257
 
258
+ @api.viewset(Book)
253
259
  class BookViewSet(APIViewSet):
254
- model = Book
255
- api = api
256
260
  pagination_class = LargePagination
257
261
  ```
258
262
 
@@ -261,6 +265,7 @@ class BookViewSet(APIViewSet):
261
265
  ## 🛠 Project Structure & Docs
262
266
 
263
267
  Documentation (MkDocs + Material):
268
+
264
269
  ```
265
270
  docs/
266
271
  getting_started/
@@ -273,17 +278,19 @@ docs/
273
278
  ```
274
279
 
275
280
  Browse full reference:
281
+
276
282
  - APIViewSet: `docs/api/views/api_view_set.md`
277
283
  - APIView: `docs/api/views/api_view.md`
278
284
  - ModelSerializer: `docs/api/models/model_serializer.md`
279
285
  - Authentication: `docs/api/authentication.md`
280
- - Pagination: `docs/api/pagination.md`
286
+ - Example repository: https://github.com/caspel26/ninja-aio-blog-example
281
287
 
282
288
  ---
283
289
 
284
290
  ## 🧪 Tests
285
291
 
286
292
  Use Django test runner + async ORM patterns. Example async pattern:
293
+
287
294
  ```python
288
295
  obj = await Book.objects.acreate(title="T1", published=True)
289
296
  count = await Book.objects.acount()
@@ -323,6 +330,7 @@ class ReadOnlyBookViewSet(APIViewSet):
323
330
  ## ⭐ Support
324
331
 
325
332
  Star the repo or donate:
333
+
326
334
  - [Buy me a coffee](https://buymeacoffee.com/caspel26)
327
335
 
328
336
  ---
@@ -335,11 +343,12 @@ MIT License. See [LICENSE](LICENSE).
335
343
 
336
344
  ## 🔗 Quick Links
337
345
 
338
- | Item | Link |
339
- |------|------|
340
- | PyPI | https://pypi.org/project/django-ninja-aio-crud/ |
341
- | Docs | https://django-ninja-aio.com
342
- | Issues | https://github.com/caspel26/django-ninja-aio-crud/issues |
346
+ | Item | Link |
347
+ | ------- | -------------------------------------------------------- |
348
+ | PyPI | https://pypi.org/project/django-ninja-aio-crud/ |
349
+ | Docs | https://django-ninja-aio.com |
350
+ | Issues | https://github.com/caspel26/django-ninja-aio-crud/issues |
351
+ | Example | https://github.com/caspel26/ninja-aio-blog-example |
343
352
 
344
353
  ---
345
354
 
@@ -39,6 +39,7 @@ Add to your project’s dependencies and ensure Django Ninja is installed.
39
39
  ## 🚀 Quick Start
40
40
 
41
41
  models.py
42
+
42
43
  ```python
43
44
  from django.db import models
44
45
  from ninja_aio.models import ModelSerializer
@@ -58,6 +59,7 @@ class Book(ModelSerializer):
58
59
  ```
59
60
 
60
61
  views.py
62
+
61
63
  ```python
62
64
  from ninja_aio import NinjaAIO
63
65
  from ninja_aio.views import APIViewSet
@@ -91,6 +93,7 @@ class BookViewSet(APIViewSet):
91
93
  ```
92
94
 
93
95
  Request:
96
+
94
97
  ```
95
98
  GET /book/?published=true&title=python
96
99
  ```
@@ -133,6 +136,7 @@ class ArticleViewSet(APIViewSet):
133
136
  ```
134
137
 
135
138
  Endpoints:
139
+
136
140
  - `GET /article/{pk}/tag?name=dev`
137
141
  - `POST /article/{pk}/tag/` body: `{"add":[1,2],"remove":[3]}`
138
142
 
@@ -167,6 +171,7 @@ class SecureBookViewSet(APIViewSet):
167
171
  ## 📑 Lifecycle Hooks (ModelSerializer)
168
172
 
169
173
  Available on every save/delete:
174
+
170
175
  - `on_create_before_save`
171
176
  - `on_create_after_save`
172
177
  - `before_save`
@@ -215,9 +220,8 @@ class LargePagination(PageNumberPagination):
215
220
  page_size = 50
216
221
  max_page_size = 200
217
222
 
223
+ @api.viewset(Book)
218
224
  class BookViewSet(APIViewSet):
219
- model = Book
220
- api = api
221
225
  pagination_class = LargePagination
222
226
  ```
223
227
 
@@ -226,6 +230,7 @@ class BookViewSet(APIViewSet):
226
230
  ## 🛠 Project Structure & Docs
227
231
 
228
232
  Documentation (MkDocs + Material):
233
+
229
234
  ```
230
235
  docs/
231
236
  getting_started/
@@ -238,17 +243,19 @@ docs/
238
243
  ```
239
244
 
240
245
  Browse full reference:
246
+
241
247
  - APIViewSet: `docs/api/views/api_view_set.md`
242
248
  - APIView: `docs/api/views/api_view.md`
243
249
  - ModelSerializer: `docs/api/models/model_serializer.md`
244
250
  - Authentication: `docs/api/authentication.md`
245
- - Pagination: `docs/api/pagination.md`
251
+ - Example repository: https://github.com/caspel26/ninja-aio-blog-example
246
252
 
247
253
  ---
248
254
 
249
255
  ## 🧪 Tests
250
256
 
251
257
  Use Django test runner + async ORM patterns. Example async pattern:
258
+
252
259
  ```python
253
260
  obj = await Book.objects.acreate(title="T1", published=True)
254
261
  count = await Book.objects.acount()
@@ -288,6 +295,7 @@ class ReadOnlyBookViewSet(APIViewSet):
288
295
  ## ⭐ Support
289
296
 
290
297
  Star the repo or donate:
298
+
291
299
  - [Buy me a coffee](https://buymeacoffee.com/caspel26)
292
300
 
293
301
  ---
@@ -300,10 +308,11 @@ MIT License. See [LICENSE](LICENSE).
300
308
 
301
309
  ## 🔗 Quick Links
302
310
 
303
- | Item | Link |
304
- |------|------|
305
- | PyPI | https://pypi.org/project/django-ninja-aio-crud/ |
306
- | Docs | https://django-ninja-aio.com
307
- | Issues | https://github.com/caspel26/django-ninja-aio-crud/issues |
311
+ | Item | Link |
312
+ | ------- | -------------------------------------------------------- |
313
+ | PyPI | https://pypi.org/project/django-ninja-aio-crud/ |
314
+ | Docs | https://django-ninja-aio.com |
315
+ | Issues | https://github.com/caspel26/django-ninja-aio-crud/issues |
316
+ | Example | https://github.com/caspel26/ninja-aio-blog-example |
308
317
 
309
318
  ---
@@ -50,9 +50,8 @@ Attach decorators to CRUD operations without redefining views:
50
50
  ```python
51
51
  from ninja_aio.schemas.helpers import DecoratorsSchema
52
52
 
53
+ @api.viewset(MyModel)
53
54
  class MyViewSet(APIViewSet):
54
- api = api
55
- model = MyModel
56
55
  extra_decorators = DecoratorsSchema(
57
56
  list=[require_auth, cache_page(30)],
58
57
  retrieve=[require_auth],
@@ -33,55 +33,54 @@ Traditional Django REST development requires:
33
33
  **Django Ninja Aio CRUD** eliminates this complexity:
34
34
 
35
35
  === "Traditional Approach"
36
- ```python
36
+ ```python
37
37
  # schema.py
38
38
  class UserSchemaOut(ModelSchema)
39
39
  class Meta:
40
- model = User
41
- fields = ['id', 'username', 'email']
42
-
40
+ model = User
41
+ fields = ['id', 'username', 'email']
42
+
43
43
  class UserSchemaIn(ModelSchema):
44
44
  class Meta:
45
45
  model = User
46
46
  fields = ['username', 'email', 'password']
47
-
47
+
48
48
  # views.py
49
49
  @api.get("/users", response={200: list[UserSchemaOut]})
50
50
  async def list_users(request):
51
51
  return [user async for user in User.objects.select_related().all()]
52
-
52
+
53
53
  @api.post("/users/", response={201: UserSchemaOut})
54
54
  async def create_user(request, data: UserSchemaIn):
55
55
  user = await User.objects.select_related().acreate(**data.model_dump())
56
56
  return 201, user
57
57
 
58
-
58
+
59
59
  # ... more views for retrieve, update, delete
60
60
  ```
61
61
 
62
62
  === "Django Ninja Aio CRUD"
63
- ```python
63
+ ```python
64
64
  # models.py
65
65
  class User(ModelSerializer):
66
66
  username = models.CharField(max_length=150)
67
67
  email = models.EmailField()
68
68
  password = models.CharField(max_length=128)
69
-
69
+
70
70
  class ReadSerializer:
71
71
  fields = ["id", "username", "email"]
72
-
72
+
73
73
  class CreateSerializer:
74
74
  fields = ["username", "email", "password"]
75
-
75
+
76
76
  class UpdateSerializer:
77
77
  optionals = [("email", str)]
78
-
78
+
79
79
  # views.py
80
+ @api.viewset(User)
80
81
  class UserViewSet(APIViewSet):
81
- model = User
82
- api = api
83
-
84
- UserViewSet().add_views_to_route()
82
+ pass
83
+
85
84
  # Done! List, Create, Retrieve, Update, Delete endpoints ready
86
85
  ```
87
86
 
@@ -213,19 +212,18 @@ from .models import Author, Category, Article, Tag
213
212
  api = NinjaAIO(title="Blog API", version="1.0.0")
214
213
 
215
214
 
215
+ @api.viewset(Author)
216
216
  class AuthorViewSet(APIViewSet):
217
- model = Author
218
- api = api
217
+ pass
219
218
 
220
219
 
220
+ @api.viewset(Category)
221
221
  class CategoryViewSet(APIViewSet):
222
- model = Category
223
- api = api
222
+ pass
224
223
 
225
224
 
225
+ @api.viewset(Article)
226
226
  class ArticleViewSet(APIViewSet):
227
- model = Article
228
- api = api
229
227
  query_params = {
230
228
  "is_published": (bool, None),
231
229
  "category": (int, None),
@@ -242,16 +240,9 @@ class ArticleViewSet(APIViewSet):
242
240
  return queryset
243
241
 
244
242
 
243
+ @api.viewset(Tag)
245
244
  class TagViewSet(APIViewSet):
246
- model = Tag
247
- api = api
248
-
249
-
250
- # Register all views
251
- AuthorViewSet().add_views_to_route()
252
- CategoryViewSet().add_views_to_route()
253
- ArticleViewSet().add_views_to_route()
254
- TagViewSet().add_views_to_route()
245
+ pass
255
246
  ```
256
247
 
257
248
  This creates a complete blog API with:
@@ -287,9 +278,9 @@ class User(ModelSerializer):
287
278
  Automatically generates complete CRUD endpoints:
288
279
 
289
280
  ```python
281
+ @api.viewset(User)
290
282
  class UserViewSet(APIViewSet):
291
- model = User
292
- api = api
283
+ pass
293
284
  # Generates: List, Create, Retrieve, Update, Delete
294
285
  ```
295
286
 
@@ -298,17 +289,16 @@ class UserViewSet(APIViewSet):
298
289
  Extend with custom endpoints:
299
290
 
300
291
  ```python
292
+ from ninja_aio.decorators import api_post
293
+
294
+ @api.viewset(User)
301
295
  class UserViewSet(APIViewSet):
302
- model = User
303
- api = api
304
-
305
- def views(self):
306
- @self.router.post("/{pk}/activate/")
307
- async def activate(request, pk: int):
308
- user = await User.objects.aget(pk=pk)
309
- user.is_active = True
310
- await user.asave()
311
- return {"message": "User activated"}
296
+ @api_post("/{pk}/activate")
297
+ async def activate(self, request, pk: int):
298
+ user = await User.objects.aget(pk=pk)
299
+ user.is_active = True
300
+ await user.asave()
301
+ return {"message": "User activated"}
312
302
  ```
313
303
 
314
304
  ## 📄 License
@@ -327,6 +317,7 @@ If you find Django Ninja Aio CRUD useful, consider supporting the project:
327
317
  - **GitHub:** [https://github.com/caspel26/django-ninja-aio-crud](https://github.com/caspel26/django-ninja-aio-crud)
328
318
  - **PyPI:** [https://pypi.org/project/django-ninja-aio-crud/](https://pypi.org/project/django-ninja-aio-crud/)
329
319
  - **Django Ninja:** [https://django-ninja.dev/](https://django-ninja.dev/)
320
+ - **Example repository:** https://github.com/caspel26/ninja-aio-blog-example
330
321
 
331
322
  ---
332
323
 
@@ -1,6 +1,6 @@
1
1
  """Django Ninja AIO CRUD - Rest Framework"""
2
2
 
3
- __version__ = "2.3.0"
3
+ __version__ = "2.3.2"
4
4
 
5
5
  from .api import NinjaAIO
6
6
 
@@ -6,6 +6,7 @@ import orjson
6
6
  from django.http import HttpRequest
7
7
  from django.conf import settings
8
8
  from ninja.renderers import BaseRenderer
9
+ from pydantic import AnyUrl
9
10
 
10
11
 
11
12
  class ORJSONRenderer(BaseRenderer):
@@ -38,7 +39,7 @@ class ORJSONRenderer(BaseRenderer):
38
39
  def transform(cls, value):
39
40
  if isinstance(value, bytes):
40
41
  return base64.b64encode(value).decode()
41
- if isinstance(value, (IPv4Address, IPv6Address)):
42
+ if isinstance(value, (IPv4Address, IPv6Address, AnyUrl)):
42
43
  return str(value)
43
44
  if isinstance(value, dict):
44
45
  return {k: cls.transform(v) for k, v in value.items()}
@@ -28,9 +28,9 @@ classifiers = [
28
28
  "Topic :: Internet :: WWW/HTTP",
29
29
  ]
30
30
 
31
- requires = ["django-ninja >=1.3.0, <=1.5.1", "joserfc >=1.0.0, <= 1.4.1", "orjson >= 3.10.7, <= 3.11.5"]
31
+ requires = ["django-ninja >=1.3.0, <1.6", "joserfc >=1.0.0, <= 1.4.1", "orjson >= 3.10.7, <= 3.11.5"]
32
32
  description-file = "README.md"
33
- requires-python = ">=3.10, <=3.14"
33
+ requires-python = ">=3.10, <3.15"
34
34
 
35
35
  [tool.flit.metadata.requires-extra]
36
36
  test = [
@@ -1,35 +0,0 @@
1
- # Base usage example with a User model without any relation.
2
-
3
- from django.db import models
4
- from ninja_aio.models import ModelSerializer
5
-
6
-
7
- class User(ModelSerializer):
8
- username = models.CharField(max_length=150, unique=True)
9
- email = models.EmailField(unique=True)
10
- first_name = models.CharField(max_length=30, blank=True)
11
- last_name = models.CharField(max_length=30, blank=True)
12
-
13
- @property
14
- def full_name(self):
15
- return f"{self.first_name} {self.last_name}"
16
-
17
- class ReadSerializer:
18
- fields = ["id", "username", "email"]
19
- customs = [
20
- ("full_name", str, ""),
21
- ]
22
-
23
- class CreateSerializer:
24
- fields = ["username", "email"]
25
- optionals = [("first_name", str), ("last_name", str)]
26
-
27
- class UpdateSerializer:
28
- optionals = [
29
- ("email", str),
30
- ("first_name", str),
31
- ("last_name", str),
32
- ]
33
-
34
- def __str__(self):
35
- return self.username
@@ -1,11 +0,0 @@
1
- # Basic urls configuration for the example app
2
-
3
- from django.contrib import admin
4
- from django.urls import path
5
-
6
- from examples.ex_1.views import api
7
-
8
- urlpatterns = [
9
- path("admin/", admin.site.urls),
10
- path("api/v1/", api.urls),
11
- ]
@@ -1,16 +0,0 @@
1
- # base example of a ViewSet using NinjaAIO and APIViewSet without any relation and auth.
2
-
3
- from ninja_aio import NinjaAIO
4
- from ninja_aio.views import APIViewSet
5
-
6
- from examples.ex_1.models import User
7
-
8
- api = NinjaAIO()
9
-
10
-
11
- class UserViewSet(APIViewSet):
12
- model = User
13
- api = api
14
-
15
-
16
- UserViewSet().add_views_to_route()
@@ -1,33 +0,0 @@
1
- # Base usage example of a JWT authentication setup with NinjaAIO.
2
-
3
- from ninja_aio.auth import AsyncJwtBearer
4
- from ninja_aio.models import ModelUtil
5
- from django.conf import settings
6
- from joserfc import jwk
7
-
8
- from examples.ex_2.models import Customer
9
-
10
-
11
- PUBLIC_KEY: jwk.RSAKey = settings.JWT_PUBLIC_KEY
12
- ESSENTIAL_CLAIM = {"essential": True}
13
- MANDATORY_CLAIMS = {
14
- "iat": ESSENTIAL_CLAIM,
15
- "exp": ESSENTIAL_CLAIM,
16
- "nbf": ESSENTIAL_CLAIM,
17
- "aud": ESSENTIAL_CLAIM,
18
- "sub": ESSENTIAL_CLAIM,
19
- }
20
-
21
-
22
- class JwtAuth(AsyncJwtBearer):
23
- jwt_public = PUBLIC_KEY
24
- claims = MANDATORY_CLAIMS
25
-
26
- async def auth_handler(self, request):
27
- try:
28
- request.user = await ModelUtil(Customer).get_object(
29
- request, self.dcd.claims.get("sub", ""), with_qs_request=False
30
- )
31
- except Customer.DoesNotExist:
32
- return False
33
- return True
@@ -1,62 +0,0 @@
1
- # Base usage example with a User model with Customer ForeignKey.
2
-
3
- from django.db import models
4
- from ninja_aio.models import ModelSerializer
5
-
6
-
7
- class Customer(ModelSerializer):
8
- name = models.CharField(max_length=255)
9
- email = models.EmailField(unique=True)
10
-
11
- users: models.QuerySet["User"]
12
-
13
- class ReadSerializer:
14
- # Note: 'users' field will represent related User instances as list of their RelatedSerializer data
15
- # This is automatically handled by NinjaAIO's ModelSerializer
16
- fields = ["id", "name", "email", "users"]
17
-
18
- class CreateSerializer:
19
- fields = ["name", "email"]
20
-
21
- class UpdateSerializer:
22
- optionals = [
23
- ("name", str),
24
- ("email", str),
25
- ]
26
-
27
- def __str__(self):
28
- return self.name
29
-
30
-
31
- class User(ModelSerializer):
32
- username = models.CharField(max_length=150, unique=True)
33
- email = models.EmailField(unique=True)
34
- first_name = models.CharField(max_length=30, blank=True)
35
- last_name = models.CharField(max_length=30, blank=True)
36
- customer = models.ForeignKey(
37
- Customer, on_delete=models.CASCADE, related_name="users"
38
- )
39
-
40
- @property
41
- def full_name(self):
42
- return f"{self.first_name} {self.last_name}"
43
-
44
- class ReadSerializer:
45
- fields = ["id", "username", "email", "customer"]
46
- customs = [
47
- ("full_name", str, ""),
48
- ]
49
-
50
- class CreateSerializer:
51
- fields = ["username", "email", "customer"]
52
- optionals = [("first_name", str), ("last_name", str)]
53
-
54
- class UpdateSerializer:
55
- optionals = [
56
- ("email", str),
57
- ("first_name", str),
58
- ("last_name", str),
59
- ]
60
-
61
- def __str__(self):
62
- return self.username
@@ -1,11 +0,0 @@
1
- # Basic urls configuration for the example app
2
-
3
- from django.contrib import admin
4
- from django.urls import path
5
-
6
- from examples.ex_2.views import api
7
-
8
- urlpatterns = [
9
- path("admin/", admin.site.urls),
10
- path("api/v1/", api.urls),
11
- ]
@@ -1,26 +0,0 @@
1
- # base example of a ViewSet using NinjaAIO and APIViewSet without any relation and auth.
2
-
3
- from ninja_aio import NinjaAIO
4
- from ninja_aio.views import APIViewSet
5
-
6
- from examples.ex_2 import models
7
- from examples.ex_2.auth import JwtAuth
8
-
9
- api = NinjaAIO()
10
-
11
-
12
- class BaseAPIViewSet(APIViewSet):
13
- api = api
14
- auth = [JwtAuth()]
15
-
16
-
17
- class CustomerViewSet(BaseAPIViewSet):
18
- model = models.Customer
19
-
20
-
21
- class UserViewSet(BaseAPIViewSet):
22
- model = models.User
23
-
24
-
25
- CustomerViewSet().add_views_to_route()
26
- UserViewSet().add_views_to_route()