django-ninja-aio-crud 0.10.2__py3-none-any.whl → 2.4.0__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,526 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: django-ninja-aio-crud
3
- Version: 0.10.2
4
- Summary: Django Ninja AIO CRUD - Rest Framework
5
- Author: Giuseppe Casillo
6
- Requires-Python: >=3.10
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 :: Only
21
- Classifier: Framework :: Django
22
- Classifier: Framework :: AsyncIO
23
- Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
24
- Classifier: Topic :: Internet :: WWW/HTTP
25
- License-File: LICENSE
26
- Requires-Dist: django-ninja >=1.3.0
27
- Requires-Dist: joserfc >=1.0.0
28
- Requires-Dist: orjson >= 3.10.7
29
- Requires-Dist: coverage ; extra == "test"
30
- Project-URL: Repository, https://github.com/caspel26/django-ninja-aio-crud
31
- Provides-Extra: test
32
-
33
- # 🥷 django-ninja-aio-crud
34
- ![Test](https://github.com/caspel26/django-ninja-aio-crud/actions/workflows/coverage.yml/badge.svg)
35
- [![codecov](https://codecov.io/gh/caspel26/django-ninja-aio-crud/graph/badge.svg?token=DZ5WDT3S20)](https://codecov.io/gh/caspel26/django-ninja-aio-crud)
36
- [![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/)
37
- [![PyPI - License](https://img.shields.io/pypi/l/django-ninja-aio-crud)](https://github.com/caspel26/django-ninja-aio-crud/blob/main/LICENSE)
38
- [![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)
39
- > [!NOTE]
40
- > Django ninja aio crud framework is based on **<a href="https://django-ninja.dev/">Django Ninja framework</a>**. It comes out with built-in views and models which are able to make automatic async CRUD operations and codes views class based making the developers' life easier and the code cleaner.
41
-
42
- ## 📝 Instructions
43
-
44
- ### 📚 Prerequisites
45
-
46
- - Install Python from the [official website](https://www.python.org/) (latest version) and ensure it is added to the system Path and environment variables.
47
-
48
- ### 💻 Setup your environment
49
-
50
- - Create a virtual environment
51
- ```bash
52
- python -m venv .venv
53
- ```
54
-
55
- ### ✅ Activate it
56
-
57
- - If you are from linux activate it with
58
-
59
- ```bash
60
- . .venv/bin/activate
61
- ```
62
-
63
- - If you are from windows activate it with
64
-
65
- ```bash
66
- . .venv/Scripts/activate
67
- ```
68
-
69
- ### 📥 Install package
70
-
71
- ```bash
72
- pip install django-ninja-aio-crud
73
- ```
74
-
75
- ## 🚀 Usage
76
-
77
- > [!TIP]
78
- > If you find **django ninja aio crud** useful, consider :star: this project
79
- > and why not ... [Buy me a coffee](https://buymeacoffee.com/caspel26)
80
-
81
- ### ModelSerializer
82
-
83
- - You can serialize your models using ModelSerializer and made them inherit from it. In your models.py import ModelSerializer
84
- ```python
85
- # models.py
86
- from django.db import models
87
- from ninja_aio.models import ModelSerializer
88
-
89
-
90
- class Foo(ModelSerializer):
91
- name = models.CharField(max_length=30)
92
- bar = models.CharField(max_length=30)
93
-
94
- class ReadSerializer:
95
- fields = ["id", "name", "bar"]
96
-
97
- class CreateSerializer:
98
- fields = ["name", "bar"]
99
-
100
- class UpdateSerializer:
101
- fields = ["name", "bar"]
102
- ```
103
-
104
- - ReadSerializer, CreateSerializer, UpdateSerializer are used to define which fields would be included in runtime schemas creation. You can also specify custom fields and handle their function by overriding custom_actions ModelSerializer's method.
105
-
106
- ```python
107
- # models.py
108
- from django.db import models
109
- from ninja_aio.models import ModelSerializer
110
-
111
-
112
- class Foo(ModelSerializer):
113
- name = models.CharField(max_length=30)
114
- bar = models.CharField(max_length=30)
115
- active = models.BooleanField(default=False)
116
-
117
- class ReadSerializer:
118
- fields = ["id", "name", "bar"]
119
-
120
- class CreateSerializer:
121
- customs = [("force_activation", bool, False)]
122
- fields = ["name", "bar"]
123
-
124
- class UpdateSerializer:
125
- fields = ["name", "bar"]
126
-
127
- async def custom_actions(self, payload: dict[str, Any]):
128
- if not payload.get("force_activation"):
129
- return
130
- setattr(self, "force_activation", True)
131
-
132
- async def post_create(self) -> None:
133
- if not hasattr(self, "force_activation") or not getattr(self, "force_activation"):
134
- return
135
- self.active = True
136
- await self.asave()
137
- ```
138
-
139
- - post create method is a custom method that comes out to handle actions which will be excuted after that the object is created. It can be used, indeed, for example to handle custom fields' actions.
140
-
141
- - You can also define optional fields for you Create and Update serializers. To declare an optional fields you have to give the field type too.
142
- ```python
143
- # models.py
144
- from django.db import models
145
- from ninja_aio.models import ModelSerializer
146
-
147
-
148
- class Foo(ModelSerializer):
149
- name = models.CharField(max_length=30)
150
- bar = models.CharField(max_length=30, default="")
151
- active = models.BooleanField(default=False)
152
-
153
- class ReadSerializer:
154
- fields = ["id", "name", "bar"]
155
-
156
- class CreateSerializer:
157
- fields = ["name"]
158
- optionals = [("bar", str), ("active", bool)]
159
-
160
- class UpdateSerializer:
161
- optionals = [("bar", str), ("active", bool)]
162
- ```
163
-
164
- - Instead of declaring your fields maybe you want to exclude some of them. Declaring "excludes" attribute into serializers will exclude the given fields. (You can declare only one between "fields" and "excludes").
165
-
166
- ```python
167
- # models.py
168
- from django.db import models
169
- from ninja_aio.models import ModelSerializer
170
-
171
-
172
- class Foo(ModelSerializer):
173
- name = models.CharField(max_length=30)
174
- bar = models.CharField(max_length=30, default="")
175
- active = models.BooleanField(default=False)
176
-
177
- class ReadSerializer:
178
- excludes = ["bar"]
179
-
180
- class CreateSerializer:
181
- fields = ["name"]
182
- optionals = [("bar", str), ("active", bool)]
183
-
184
- class UpdateSerializer:
185
- excludes = ["id", "name"]
186
- optionals = [("bar", str), ("active", bool)]
187
- ```
188
- - If you want to add into ReadSerializer model properties you must define them as customs.
189
- ```python
190
- # models.py
191
- from django.db import models
192
- from ninja_aio.models import ModelSerializer
193
-
194
-
195
- class Foo(ModelSerializer):
196
- name = models.CharField(max_length=30)
197
- bar = models.CharField(max_length=30, default="")
198
- active = models.BooleanField(default=False)
199
-
200
- @property
201
- def full_name(self):
202
- return f"{self.name} example_full_name"
203
-
204
- class ReadSerializer:
205
- excludes = ["bar"]
206
- customs = [("full_name", str, "")]
207
-
208
- class CreateSerializer:
209
- fields = ["name"]
210
- optionals = [("bar", str), ("active", bool)]
211
-
212
- class UpdateSerializer:
213
- excludes = ["id", "name"]
214
- optionals = [("bar", str), ("active", bool)]
215
- ```
216
- - ModelSerializer comes out also with methods executed on object save and delete, them are:
217
-
218
- 1. on_create_before_save: code executed on object creation but before saving;
219
- 1. on_create_after_save: code executed on object creation but after saving;
220
- 1. before_save: code executed on every save but before saving;
221
- 1. after_save: code executed on every save but after saving;
222
- 1. on_delete: code executed after object delete;
223
-
224
-
225
- ### APIViewSet
226
-
227
- - View class used to automatically generate CRUD views. in your views.py import APIViewSet and define your api using NinjaAIO class. NinjaAIO class uses built-in parser and renderer which use orjson for data serialization.
228
-
229
- ```python
230
- # views.py
231
- from ninja_aio import NinjaAIO
232
- from ninja_aio.views import APIViewSet
233
-
234
- from .models import Foo
235
-
236
- api = NinjaAIO()
237
-
238
-
239
- class FooAPI(APIViewSet):
240
- model = Foo
241
- api = api
242
-
243
-
244
- FooAPI().add_views_to_route()
245
- ```
246
-
247
- - and that's it, your model CRUD will be automatically created. You can also add custom views to CRUD overriding the built-in method "views".
248
-
249
- ```python
250
- # views.py
251
- from ninja import Schema
252
- from ninja_aio import NinjaAIO
253
- from ninja_aio.views import APIViewSet
254
-
255
- from .models import Foo
256
-
257
- api = NinjaAIO()
258
-
259
-
260
- class ExampleSchemaOut(Schema):
261
- sum: float
262
-
263
-
264
- class ExampleSchemaIn(Schema):
265
- n1: float
266
- n2: float
267
-
268
-
269
- class FooAPI(APIViewSet):
270
- model = Foo
271
- api = api
272
-
273
- def views(self):
274
- @self.router.post("numbers-sum/", response={200: ExampleSchemaOut})
275
- async def sum(request: HttpRequest, data: ExampleSchemaIn):
276
- return 200, {sum: data.n1 + data.n2}
277
-
278
-
279
- FooAPI().add_views_to_route()
280
- ```
281
-
282
- - You can also choose to disable any operation from crud by declaring "disbale" attribute. You can give "all" to disable every crud operation except for additional views.
283
-
284
- > [!TIP]
285
- > You can exclude by default an endpoint without declaring the serializer.
286
- > For example if you don't want to give update method to a CRUD just do not declare UpdateSerializer into model.
287
-
288
- ```python
289
- # views.py
290
- from ninja_aio import NinjaAIO
291
- from ninja_aio.views import APIViewSet
292
-
293
- from .models import Foo
294
-
295
- api = NinjaAIO()
296
-
297
-
298
- class FooAPI(APIViewSet):
299
- model = Foo
300
- api = api
301
- disable = ["retrieve", "update"]
302
-
303
-
304
- FooAPI().add_views_to_route()
305
- ```
306
- For the list endpoint you can also set query params and handle them. They will be also visible into swagger.
307
-
308
- ```python
309
- # views.py
310
- from ninja_aio import NinjaAIO
311
- from ninja_aio.views import APIViewSet
312
-
313
- from .models import Foo
314
-
315
- api = NinjaAIO()
316
-
317
-
318
- class FooAPI(APIViewSet):
319
- model = Foo
320
- api = api
321
- query_params = {"name": (str, None), "active": (bool, None)}
322
-
323
- async def query_params_handler(self, queryset, filters):
324
- return queryset.filter(**{k: v for k, v in filters.items() if v is not None})
325
-
326
-
327
- FooAPI().add_views_to_route()
328
- ```
329
-
330
- ### APIView
331
-
332
- - View class to code generic views class based. In your views.py import APIView class.
333
-
334
- ```python
335
- # views.py
336
- from ninja import Schema
337
- from ninja_aio import NinjaAIO
338
- from ninja_aio.views import APIView
339
-
340
- api = NinjaAIO()
341
-
342
-
343
- class ExampleSchemaOut(Schema):
344
- sum: float
345
-
346
-
347
- class ExampleSchemaIn(Schema):
348
- n1: float
349
- n2: float
350
-
351
-
352
- class SumView(APIView):
353
- api = api
354
- api_router_path = "numbers-sum/"
355
- router_tag = "Sum"
356
-
357
- def views(self):
358
- @self.router.post("/", response={200: ExampleSchemaOut})
359
- async def sum(request: HttpRequest, data: ExampleSchemaIn):
360
- return 200, {sum: data.n1 + data.n2}
361
-
362
-
363
- SumView().add_views_to_route()
364
- ```
365
-
366
- ### Relations
367
- - You can also set ForeignKey, OneToOne and ManyToMany relations into serialization(reverse relations are supported too). Django ninja aio crud will serialize every of these relation automatically.
368
-
369
- - Define models:
370
-
371
- ```python
372
- # models.py
373
- class Bar(ModelSerializer):
374
- name = models.CharField(max_length=30)
375
- description = models.TextField(max_length=30)
376
-
377
- # ReadSerializer with reverse OneToMany relation (foos)
378
- class ReadSerializer:
379
- fields = ["id", "name", "description", "foos"]
380
-
381
- class CreateSerializer:
382
- fields = ["name", "description"]
383
-
384
- class UpdateSerializer:
385
- fields = ["name", "description"]
386
-
387
-
388
- class Foo(ModelSerializer):
389
- name = models.CharField(max_length=30)
390
- bar = models.ForeignKey(Bar, on_delete=models.CASCADE, related_name="foos")
391
-
392
- class ReadSerializer:
393
- fields = ["id", "name", "bar"]
394
-
395
- class CreateSerializer:
396
- fields = ["name", "bar"]
397
-
398
- class UpdateSerializer:
399
- fields = ["name"]
400
- ```
401
-
402
- - Define views:
403
-
404
- ```python
405
- # views.py
406
- from ninja_aio import NinjaAIO
407
- from ninja_aio.views import APIViewSet
408
-
409
- from .models import Foo, Bar
410
-
411
- api = NinjaAIO()
412
-
413
-
414
- class FooAPI(APIViewSet):
415
- model = Foo
416
- api = api
417
-
418
-
419
- class BarAPI(APIViewSet):
420
- model = Bar
421
- api = api
422
-
423
-
424
- FooAPI().add_views_to_route()
425
- BarAPI().add_views_to_route()
426
- ```
427
-
428
- - Now run your server and go to /docs url:
429
-
430
- ### Docs
431
-
432
- - Foo Schemas
433
-
434
- ![Swagger UI](docs/images/foo-swagger.png)
435
-
436
- - Bar Schemas with reverse relation
437
-
438
- ![Swagger UI](docs/images/bar-swagger.png)
439
-
440
- ## 🔒 Authentication
441
-
442
- ### Jwt
443
-
444
- - AsyncJWTBearer built-in class is an authenticator class which use joserfc module. It cames out with authenticate method which validate given claims. Override auth handler method to write your own authentication method. Default algorithms used is RS256. a jwt Token istance is set as class atribute so you can use it by self.dcd.
445
-
446
- ```python
447
- from ninja_aio.auth import AsyncJWTBearer
448
- from django.conf import settings
449
- from django.http import HttpRequest
450
-
451
- from .models import Foo
452
-
453
-
454
- class CustomJWTBearer(AsyncJWTBearer):
455
- jwt_public = settings.JWT_PUBLIC
456
- claims = {"foo_id": {"essential": True}}
457
-
458
- async def auth_handler(self, request: HttpRequest):
459
- try:
460
- request.user = await Foo.objects.aget(id=self.dcd.claims["foo_id"])
461
- except Foo.DoesNotExist:
462
- return None
463
- return request.user
464
- ```
465
-
466
- - Then add it to views.
467
-
468
- ```python
469
- # views.py
470
- from ninja import Schema
471
- from ninja_aio import NinjaAIO
472
- from ninja_aio.views import APIViewSet, APIView
473
-
474
- from .models import Foo
475
-
476
- api = NinjaAIO()
477
-
478
-
479
- class FooAPI(APIViewSet):
480
- model = Foo
481
- api = api
482
- auth = CustomJWTBearer()
483
-
484
-
485
- class ExampleSchemaOut(Schema):
486
- sum: float
487
-
488
-
489
- class ExampleSchemaIn(Schema):
490
- n1: float
491
- n2: float
492
-
493
-
494
- class SumView(APIView):
495
- api = api
496
- api_router_path = "numbers-sum/"
497
- router_tag = "Sum"
498
- auth = CustomJWTBearer()
499
-
500
- def views(self):
501
- @self.router.post("/", response={200: ExampleSchemaOut}, auth=self.auth)
502
- async def sum(request: HttpRequest, data: ExampleSchemaIn):
503
- return 200, {sum: data.n1 + data.n2}
504
-
505
-
506
- FooAPI().add_views_to_route()
507
- SumView().add_views_to_route()
508
- ```
509
-
510
- ## 📝 Pagination
511
-
512
- - By default APIViewSet list view uses Django Ninja built-in AsyncPagination class "PageNumberPagination". You can customize and assign it to APIViewSet class. To make your custom pagination consult **<a href="https://django-ninja.dev/guides/response/pagination/#async-pagination">Django Ninja pagination documentation</a>**.
513
-
514
- ```python
515
- # views.py
516
-
517
- class FooAPI(APIViewSet):
518
- model = Foo
519
- api = api
520
- pagination_class = CustomPaginationClass
521
-
522
- ```
523
-
524
- ## 📌 Notes
525
- - Feel free to contribute and improve the program. 🛠️
526
-
@@ -1,14 +0,0 @@
1
- ninja_aio/__init__.py,sha256=kXlRrvKYNdU9gmbossk8GM22iSY4k_go-OeZVJlQyn4,120
2
- ninja_aio/api.py,sha256=Fe6l3YCy7MW5TY4-Lbl80CFuK2NT2Y7tHfmqPk6Mqak,1735
3
- ninja_aio/auth.py,sha256=c_ILAySswjbSIqnE9Y0G5n1qreXzAtSAaWfrhyer-i8,1283
4
- ninja_aio/exceptions.py,sha256=gPnZX1Do2GXudbU8wDYkwhO70Qj0ZNrIJJ2UXRs9vYk,2241
5
- ninja_aio/models.py,sha256=lMipICWuLV5zETVp56b-29R-P0gBWEzXT_z3uaTlkYE,18769
6
- ninja_aio/parsers.py,sha256=e_4lGCPV7zs-HTqtdJTc8yQD2KPAn9njbL8nF_Mmgkc,153
7
- ninja_aio/renders.py,sha256=0eYklRKd59aV4cZDom5vLZyA99Ob17OwkpMybsRXvyg,1970
8
- ninja_aio/schemas.py,sha256=Fzu2ko3kUxkOnrjG5QYdmOXZd2gcpYGjVuocCW44NfQ,473
9
- ninja_aio/types.py,sha256=TJSGlA7bt4g9fvPhJ7gzH5tKbLagPmZUzfgttEOp4xs,468
10
- ninja_aio/views.py,sha256=Mb38z0QS9Iwe-qB9wuuxcfCOJymRI9SppbHOfns6yHg,20944
11
- django_ninja_aio_crud-0.10.2.dist-info/licenses/LICENSE,sha256=yrDAYcm0gRp_Qyzo3GQa4BjYjWRkAhGC8QRva__RYq0,1073
12
- django_ninja_aio_crud-0.10.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
13
- django_ninja_aio_crud-0.10.2.dist-info/METADATA,sha256=NkJRoyTgKiXOQfJyKu91NJqdNF3JOJxHHZQ6QC-ykeU,14139
14
- django_ninja_aio_crud-0.10.2.dist-info/RECORD,,