django-ninja-aio-crud 2.17.0__py3-none-any.whl → 2.18.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.
@@ -1,379 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: django-ninja-aio-crud
3
- Version: 2.17.0
4
- Summary: Django Ninja AIO CRUD - Rest Framework
5
- Author: Giuseppe Casillo
6
- Requires-Python: >=3.10, <3.15
7
- Description-Content-Type: text/markdown
8
- Classifier: Operating System :: OS Independent
9
- Classifier: Topic :: Internet
10
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
11
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
- Classifier: Topic :: Software Development :: Libraries
13
- Classifier: Topic :: Software Development
14
- Classifier: Environment :: Web Environment
15
- Classifier: Intended Audience :: Developers
16
- Classifier: License :: OSI Approved :: MIT License
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
- Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Programming Language :: Python :: 3.13
21
- Classifier: Programming Language :: Python :: 3.14
22
- Classifier: Programming Language :: Python :: 3 :: Only
23
- Classifier: Framework :: Django
24
- Classifier: Framework :: AsyncIO
25
- Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
26
- Classifier: Topic :: Internet :: WWW/HTTP
27
- License-File: LICENSE
28
- Requires-Dist: django-ninja >=1.3.0, <1.6
29
- Requires-Dist: joserfc >=1.0.0, <= 1.4.1
30
- Requires-Dist: orjson >= 3.10.7, <= 3.11.5
31
- Requires-Dist: coverage ; extra == "test"
32
- Project-URL: Documentation, https://django-ninja-aio.com
33
- Project-URL: Repository, https://github.com/caspel26/django-ninja-aio-crud
34
- Provides-Extra: test
35
-
36
- # 🥷 django-ninja-aio-crud
37
-
38
- ![Tests](https://github.com/caspel26/django-ninja-aio-crud/actions/workflows/coverage.yml/badge.svg)
39
- [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=caspel26_django-ninja-aio-crud&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=caspel26_django-ninja-aio-crud)
40
- [![codecov](https://codecov.io/gh/caspel26/django-ninja-aio-crud/graph/badge.svg?token=DZ5WDT3S20)](https://codecov.io/gh/caspel26/django-ninja-aio-crud/)
41
- [![PyPI - Version](https://img.shields.io/pypi/v/django-ninja-aio-crud?color=g&logo=pypi&logoColor=white)](https://pypi.org/project/django-ninja-aio-crud/)
42
- [![PyPI - License](https://img.shields.io/pypi/l/django-ninja-aio-crud)](LICENSE)
43
- [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
44
-
45
- > Lightweight async CRUD layer on top of **[Django Ninja](https://django-ninja.dev/)** with automatic schema generation, filtering, pagination, auth & Many‑to‑Many management.
46
-
47
- ---
48
-
49
- ## ✨ Features
50
-
51
- - Serializer (Meta-driven) first-class: dynamic schemas for existing Django models without inheriting ModelSerializer
52
- - Async CRUD ViewSets (create, list, retrieve, update, delete)
53
- - Automatic Pydantic schemas from `ModelSerializer` (read/create/update)
54
- - Dynamic query params (runtime schema via `pydantic.create_model`)
55
- - Per-method authentication (`auth`, `get_auth`, `post_auth`, etc.)
56
- - Async pagination (customizable)
57
- - M2M relation endpoints via `M2MRelationSchema` (add/remove/get + filters)
58
- - Reverse relation serialization
59
- - Hook methods (`query_params_handler`, `<related>_query_params_handler`, `custom_actions`, lifecycle hooks)
60
- - ORJSON renderer through `NinjaAIO`
61
- - Clean, minimal integration
62
-
63
- ---
64
-
65
- ## 🚀 Quick Start (Serializer)
66
-
67
- If you already have Django models, start with the Meta-driven Serializer for instant CRUD without changing model base classes.
68
-
69
- ```python
70
- from ninja_aio.models import serializers
71
- from ninja_aio.views import APIViewSet
72
- from ninja_aio import NinjaAIO
73
- from . import models
74
-
75
- class BookSerializer(serializers.Serializer):
76
- class Meta:
77
- model = models.Book
78
- schema_in = serializers.SchemaModelConfig(fields=["title", "published"])
79
- schema_out = serializers.SchemaModelConfig(fields=["id", "title", "published"])
80
- schema_update = serializers.SchemaModelConfig(optionals=[("title", str), ("published", bool)])
81
-
82
- api = NinjaAIO()
83
-
84
- @api.viewset(models.Book)
85
- class BookViewSet(APIViewSet):
86
- serializer_class = BookSerializer
87
- ```
88
-
89
- Visit `/docs` → CRUD endpoints ready.
90
-
91
- ---
92
-
93
- ## 🚀 Quick Start (ModelSerializer)
94
-
95
- models.py
96
-
97
- ```python
98
- from django.db import models
99
- from ninja_aio.models import ModelSerializer
100
-
101
- class Book(ModelSerializer):
102
- title = models.CharField(max_length=120)
103
- published = models.BooleanField(default=True)
104
-
105
- class ReadSerializer:
106
- fields = ["id", "title", "published"]
107
-
108
- class CreateSerializer:
109
- fields = ["title", "published"]
110
-
111
- class UpdateSerializer:
112
- optionals = [("title", str), ("published", bool)]
113
- ```
114
-
115
- views.py
116
-
117
- ```python
118
- from ninja_aio import NinjaAIO
119
- from ninja_aio.views import APIViewSet
120
- from .models import Book
121
-
122
- api = NinjaAIO()
123
-
124
- @api.viewset(Book)
125
- class BookViewSet(APIViewSet):
126
- pass
127
-
128
- ```
129
-
130
- Visit `/docs` → CRUD endpoints ready.
131
-
132
- ---
133
-
134
- ## 🔄 Query Filtering
135
-
136
- ```python
137
- @api.viewset(Book)
138
- class BookViewSet(APIViewSet):
139
- query_params = {"published": (bool, None), "title": (str, None)}
140
-
141
- async def query_params_handler(self, queryset, filters):
142
- if filters.get("published") is not None:
143
- queryset = queryset.filter(published=filters["published"])
144
- if filters.get("title"):
145
- queryset = queryset.filter(title__icontains=filters["title"])
146
- return queryset
147
- ```
148
-
149
- Request:
150
-
151
- ```
152
- GET /book/?published=true&title=python
153
- ```
154
-
155
- ---
156
-
157
- ## 🤝 Many-to-Many Example (with filters)
158
-
159
- ```python
160
- from ninja_aio.schemas import M2MRelationSchema
161
-
162
- class Tag(ModelSerializer):
163
- name = models.CharField(max_length=50)
164
- class ReadSerializer:
165
- fields = ["id", "name"]
166
-
167
- class Article(ModelSerializer):
168
- title = models.CharField(max_length=120)
169
- tags = models.ManyToManyField(Tag, related_name="articles")
170
-
171
- class ReadSerializer:
172
- fields = ["id", "title", "tags"]
173
-
174
- @api.viewset(Article)
175
- class ArticleViewSet(APIViewSet):
176
- m2m_relations = [
177
- M2MRelationSchema(
178
- model=Tag,
179
- related_name="tags",
180
- filters={"name": (str, "")}
181
- )
182
- ]
183
-
184
- async def tags_query_params_handler(self, queryset, filters):
185
- n = filters.get("name")
186
- if n:
187
- queryset = queryset.filter(name__icontains=n)
188
- return queryset
189
-
190
- ```
191
-
192
- Endpoints:
193
-
194
- - `GET /article/{pk}/tag?name=dev`
195
- - `POST /article/{pk}/tag/` body: `{"add":[1,2],"remove":[3]}`
196
-
197
- ---
198
-
199
- ## 🔐 Authentication (JWT example)
200
-
201
- ```python
202
- from ninja_aio.auth import AsyncJwtBearer
203
- from joserfc import jwk
204
- from .models import Book
205
-
206
- PUBLIC_KEY = "-----BEGIN PUBLIC KEY----- ..."
207
-
208
- class JWTAuth(AsyncJwtBearer):
209
- jwt_public = jwk.RSAKey.import_key(PUBLIC_KEY)
210
- jwt_alg = "RS256"
211
- claims = {"sub": {"essential": True}}
212
-
213
- async def auth_handler(self, request):
214
- book_id = self.dcd.claims.get("sub")
215
- return await Book.objects.aget(id=book_id)
216
-
217
- @api.viewset(Book)
218
- class SecureBookViewSet(APIViewSet):
219
- auth = [JWTAuth()]
220
- get_auth = None # list/retrieve public
221
- ```
222
-
223
- ---
224
-
225
- ## 📑 Lifecycle Hooks (ModelSerializer)
226
-
227
- Available on every save/delete:
228
-
229
- - `on_create_before_save`
230
- - `on_create_after_save`
231
- - `before_save`
232
- - `after_save`
233
- - `on_delete`
234
- - `custom_actions(payload)` (create/update custom field logic)
235
- - `post_create()` (after create commit)
236
-
237
- ---
238
-
239
- ## 🧩 Adding Custom Endpoints
240
-
241
- ```python
242
- from ninja_aio.decorators import api_get
243
-
244
- @api.viewset(Book)
245
- class BookViewSet(APIViewSet):
246
- @api_get("/stats/")
247
- async def stats(self, request):
248
- total = await Book.objects.acount()
249
- return {"total": total}
250
- ```
251
-
252
- Or
253
-
254
- ```python
255
- @api.viewset(Book)
256
- class BookViewSet(APIViewSet):
257
- def views(self):
258
- @self.router.get("/stats/")
259
- async def stats(request):
260
- total = await Book.objects.acount()
261
- return {"total": total}
262
- ```
263
-
264
- ---
265
-
266
- ## 📄 Pagination
267
-
268
- Default: `PageNumberPagination`. Override:
269
-
270
- ```python
271
- from ninja.pagination import PageNumberPagination
272
-
273
- class LargePagination(PageNumberPagination):
274
- page_size = 50
275
- max_page_size = 200
276
-
277
- @api.viewset(Book)
278
- class BookViewSet(APIViewSet):
279
- pagination_class = LargePagination
280
- ```
281
-
282
- ---
283
-
284
- ## Meta-driven Serializer (for vanilla Django models)
285
-
286
- Moved above as the primary quick start.
287
-
288
- ---
289
-
290
- ## 🛠 Project Structure & Docs
291
-
292
- Documentation (MkDocs + Material):
293
-
294
- ```
295
- docs/
296
- getting_started/
297
- tutorial/
298
- api/
299
- views/
300
- models/
301
- authentication.md
302
- pagination.md
303
- ```
304
-
305
- Browse full reference:
306
-
307
- - APIViewSet: `docs/api/views/api_view_set.md`
308
- - APIView: `docs/api/views/api_view.md`
309
- - ModelSerializer: `docs/api/models/model_serializer.md`
310
- - Authentication: `docs/api/authentication.md`
311
- - Example repository: https://github.com/caspel26/ninja-aio-blog-example
312
-
313
- ---
314
-
315
- ## 🧪 Tests
316
-
317
- Use Django test runner + async ORM patterns. Example async pattern:
318
-
319
- ```python
320
- obj = await Book.objects.acreate(title="T1", published=True)
321
- count = await Book.objects.acount()
322
- ```
323
-
324
- ---
325
-
326
- ## 🚫 Disable Operations
327
-
328
- ```python
329
- @api.viewset(Book)
330
- class ReadOnlyBookViewSet(APIViewSet):
331
- disable = ["update", "delete"]
332
- ```
333
-
334
- ---
335
-
336
- ## 📌 Performance Tips
337
-
338
- - Use `queryset_request` classmethod to prefetch
339
- - Index frequently filtered fields
340
- - Keep pagination enabled
341
- - Limit slices (`queryset = queryset[:1000]`) for heavy searches
342
-
343
- ---
344
-
345
- ## 🤲 Contributing
346
-
347
- 1. Fork
348
- 2. Create branch
349
- 3. Add tests
350
- 4. Run lint (`ruff check .`)
351
- 5. Open PR
352
-
353
- ---
354
-
355
- ## ⭐ Support
356
-
357
- Star the repo or donate:
358
-
359
- - [Buy me a coffee](https://buymeacoffee.com/caspel26)
360
-
361
- ---
362
-
363
- ## 📜 License
364
-
365
- MIT License. See [LICENSE](LICENSE).
366
-
367
- ---
368
-
369
- ## 🔗 Quick Links
370
-
371
- | Item | Link |
372
- | ------- | -------------------------------------------------------- |
373
- | PyPI | https://pypi.org/project/django-ninja-aio-crud/ |
374
- | Docs | https://django-ninja-aio.com |
375
- | Issues | https://github.com/caspel26/django-ninja-aio-crud/issues |
376
- | Example | https://github.com/caspel26/ninja-aio-blog-example |
377
-
378
- ---
379
-