django-ninja-aio-crud 0.1.4__tar.gz → 0.2.1__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.
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/PKG-INFO +17 -16
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/README.md +16 -15
- django_ninja_aio_crud-0.2.1/ninja_aio/__init__.py +7 -0
- django_ninja_aio_crud-0.2.1/ninja_aio/api.py +48 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/models.py +36 -11
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/views.py +1 -1
- django_ninja_aio_crud-0.1.4/ninja_aio/__init__.py +0 -3
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/auth.py +0 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/exceptions.py +0 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/parsers.py +0 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/renders.py +0 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/ninja_aio/schemas.py +0 -0
- {django_ninja_aio_crud-0.1.4 → django_ninja_aio_crud-0.2.1}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-ninja-aio-crud
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Django Ninja AIO CRUD - Rest Framework
|
|
5
5
|
Author: Giuseppe Casillo
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -130,20 +130,21 @@ class Foo(ModelSerializer):
|
|
|
130
130
|
|
|
131
131
|
- 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.
|
|
132
132
|
|
|
133
|
+
|
|
133
134
|
### APIViewSet
|
|
134
135
|
|
|
135
|
-
- View class used to automatically generate CRUD views. in your views.py import APIViewSet and define your api using
|
|
136
|
+
- 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.
|
|
136
137
|
|
|
137
138
|
```Python
|
|
138
139
|
# views.py
|
|
139
|
-
from
|
|
140
|
+
from ninja_aio import NinjaAIO
|
|
140
141
|
from ninja_aio.views import APIViewSet
|
|
141
142
|
from ninja_aio.parsers import ORJSONParser
|
|
142
143
|
from ninja_aio.renders import ORJSONRender
|
|
143
144
|
|
|
144
145
|
from .models import Foo
|
|
145
146
|
|
|
146
|
-
api =
|
|
147
|
+
api = NinjaAIO()
|
|
147
148
|
|
|
148
149
|
|
|
149
150
|
class FooAPI(APIViewSet):
|
|
@@ -158,14 +159,15 @@ FooAPI().add_views_to_route()
|
|
|
158
159
|
|
|
159
160
|
```Python
|
|
160
161
|
# views.py
|
|
161
|
-
from ninja import
|
|
162
|
+
from ninja import Schema
|
|
163
|
+
from ninja_aio import NinjaAIO
|
|
162
164
|
from ninja_aio.views import APIViewSet
|
|
163
165
|
from ninja_aio.parsers import ORJSONParser
|
|
164
166
|
from ninja_aio.renders import ORJSONRender
|
|
165
167
|
|
|
166
168
|
from .models import Foo
|
|
167
169
|
|
|
168
|
-
api =
|
|
170
|
+
api = NinjaAIO()
|
|
169
171
|
|
|
170
172
|
|
|
171
173
|
class ExampleSchemaOut(Schema):
|
|
@@ -196,12 +198,13 @@ FooAPI().add_views_to_route()
|
|
|
196
198
|
|
|
197
199
|
```Python
|
|
198
200
|
# views.py
|
|
199
|
-
from ninja import
|
|
201
|
+
from ninja import Schema
|
|
202
|
+
from ninja_aio import NinjaAIO
|
|
200
203
|
from ninja_aio.views import APIView
|
|
201
204
|
from ninja_aio.parsers import ORJSONParser
|
|
202
205
|
from ninja_aio.renders import ORJSONRender
|
|
203
206
|
|
|
204
|
-
api =
|
|
207
|
+
api = NinjaAIO()
|
|
205
208
|
|
|
206
209
|
|
|
207
210
|
class ExampleSchemaOut(Schema):
|
|
@@ -228,10 +231,7 @@ SumView().add_views_to_route()
|
|
|
228
231
|
```
|
|
229
232
|
|
|
230
233
|
### Relations
|
|
231
|
-
- You can also set ForeignKey and
|
|
232
|
-
|
|
233
|
-
> [!WARNING]
|
|
234
|
-
> Only ForeignKey and OneToOne relations are supported for serialization, ManyToMany relations are not supported yet.
|
|
234
|
+
- 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.
|
|
235
235
|
|
|
236
236
|
- Define models:
|
|
237
237
|
|
|
@@ -270,14 +270,14 @@ class Foo(ModelSerializer):
|
|
|
270
270
|
|
|
271
271
|
```Python
|
|
272
272
|
# views.py
|
|
273
|
-
from
|
|
273
|
+
from ninja_aio import NinjaAIO
|
|
274
274
|
from ninja_aio.views import APIViewSet
|
|
275
275
|
from ninja_aio.parsers import ORJSONParser
|
|
276
276
|
from ninja_aio.renders import ORJSONRender
|
|
277
277
|
|
|
278
278
|
from .models import Foo, Bar
|
|
279
279
|
|
|
280
|
-
api =
|
|
280
|
+
api = NinjaAIO()
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
class FooAPI(APIViewSet):
|
|
@@ -336,14 +336,15 @@ class CustomJWTBearer(AsyncJWTBearer):
|
|
|
336
336
|
|
|
337
337
|
```Python
|
|
338
338
|
# views.py
|
|
339
|
-
from ninja import
|
|
339
|
+
from ninja import Schema
|
|
340
|
+
from ninja_aio import NinjaAIO
|
|
340
341
|
from ninja_aio.views import APIViewSet, APIView
|
|
341
342
|
from ninja_aio.parsers import ORJSONParser
|
|
342
343
|
from ninja_aio.renders import ORJSONRender
|
|
343
344
|
|
|
344
345
|
from .models import Foo
|
|
345
346
|
|
|
346
|
-
api =
|
|
347
|
+
api = NinjaAIO()
|
|
347
348
|
|
|
348
349
|
|
|
349
350
|
class FooAPI(APIViewSet):
|
|
@@ -101,20 +101,21 @@ class Foo(ModelSerializer):
|
|
|
101
101
|
|
|
102
102
|
- 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.
|
|
103
103
|
|
|
104
|
+
|
|
104
105
|
### APIViewSet
|
|
105
106
|
|
|
106
|
-
- View class used to automatically generate CRUD views. in your views.py import APIViewSet and define your api using
|
|
107
|
+
- 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.
|
|
107
108
|
|
|
108
109
|
```Python
|
|
109
110
|
# views.py
|
|
110
|
-
from
|
|
111
|
+
from ninja_aio import NinjaAIO
|
|
111
112
|
from ninja_aio.views import APIViewSet
|
|
112
113
|
from ninja_aio.parsers import ORJSONParser
|
|
113
114
|
from ninja_aio.renders import ORJSONRender
|
|
114
115
|
|
|
115
116
|
from .models import Foo
|
|
116
117
|
|
|
117
|
-
api =
|
|
118
|
+
api = NinjaAIO()
|
|
118
119
|
|
|
119
120
|
|
|
120
121
|
class FooAPI(APIViewSet):
|
|
@@ -129,14 +130,15 @@ FooAPI().add_views_to_route()
|
|
|
129
130
|
|
|
130
131
|
```Python
|
|
131
132
|
# views.py
|
|
132
|
-
from ninja import
|
|
133
|
+
from ninja import Schema
|
|
134
|
+
from ninja_aio import NinjaAIO
|
|
133
135
|
from ninja_aio.views import APIViewSet
|
|
134
136
|
from ninja_aio.parsers import ORJSONParser
|
|
135
137
|
from ninja_aio.renders import ORJSONRender
|
|
136
138
|
|
|
137
139
|
from .models import Foo
|
|
138
140
|
|
|
139
|
-
api =
|
|
141
|
+
api = NinjaAIO()
|
|
140
142
|
|
|
141
143
|
|
|
142
144
|
class ExampleSchemaOut(Schema):
|
|
@@ -167,12 +169,13 @@ FooAPI().add_views_to_route()
|
|
|
167
169
|
|
|
168
170
|
```Python
|
|
169
171
|
# views.py
|
|
170
|
-
from ninja import
|
|
172
|
+
from ninja import Schema
|
|
173
|
+
from ninja_aio import NinjaAIO
|
|
171
174
|
from ninja_aio.views import APIView
|
|
172
175
|
from ninja_aio.parsers import ORJSONParser
|
|
173
176
|
from ninja_aio.renders import ORJSONRender
|
|
174
177
|
|
|
175
|
-
api =
|
|
178
|
+
api = NinjaAIO()
|
|
176
179
|
|
|
177
180
|
|
|
178
181
|
class ExampleSchemaOut(Schema):
|
|
@@ -199,10 +202,7 @@ SumView().add_views_to_route()
|
|
|
199
202
|
```
|
|
200
203
|
|
|
201
204
|
### Relations
|
|
202
|
-
- You can also set ForeignKey and
|
|
203
|
-
|
|
204
|
-
> [!WARNING]
|
|
205
|
-
> Only ForeignKey and OneToOne relations are supported for serialization, ManyToMany relations are not supported yet.
|
|
205
|
+
- 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.
|
|
206
206
|
|
|
207
207
|
- Define models:
|
|
208
208
|
|
|
@@ -241,14 +241,14 @@ class Foo(ModelSerializer):
|
|
|
241
241
|
|
|
242
242
|
```Python
|
|
243
243
|
# views.py
|
|
244
|
-
from
|
|
244
|
+
from ninja_aio import NinjaAIO
|
|
245
245
|
from ninja_aio.views import APIViewSet
|
|
246
246
|
from ninja_aio.parsers import ORJSONParser
|
|
247
247
|
from ninja_aio.renders import ORJSONRender
|
|
248
248
|
|
|
249
249
|
from .models import Foo, Bar
|
|
250
250
|
|
|
251
|
-
api =
|
|
251
|
+
api = NinjaAIO()
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
class FooAPI(APIViewSet):
|
|
@@ -307,14 +307,15 @@ class CustomJWTBearer(AsyncJWTBearer):
|
|
|
307
307
|
|
|
308
308
|
```Python
|
|
309
309
|
# views.py
|
|
310
|
-
from ninja import
|
|
310
|
+
from ninja import Schema
|
|
311
|
+
from ninja_aio import NinjaAIO
|
|
311
312
|
from ninja_aio.views import APIViewSet, APIView
|
|
312
313
|
from ninja_aio.parsers import ORJSONParser
|
|
313
314
|
from ninja_aio.renders import ORJSONRender
|
|
314
315
|
|
|
315
316
|
from .models import Foo
|
|
316
317
|
|
|
317
|
-
api =
|
|
318
|
+
api = NinjaAIO()
|
|
318
319
|
|
|
319
320
|
|
|
320
321
|
class FooAPI(APIViewSet):
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Any, Sequence
|
|
2
|
+
|
|
3
|
+
from ninja.router import Router
|
|
4
|
+
from ninja.throttling import BaseThrottle
|
|
5
|
+
from ninja import NinjaAPI
|
|
6
|
+
from ninja.openapi.docs import DocsBase, Swagger
|
|
7
|
+
from ninja.constants import NOT_SET, NOT_SET_TYPE
|
|
8
|
+
|
|
9
|
+
from ninja_aio.parsers import ORJSONParser
|
|
10
|
+
from ninja_aio.renders import ORJSONRenderer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NinjaAIO(NinjaAPI):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
title: str = "NinjaAPI",
|
|
17
|
+
version: str = "1.0.0",
|
|
18
|
+
description: str = "",
|
|
19
|
+
openapi_url: str | None = "/openapi.json",
|
|
20
|
+
docs: DocsBase = Swagger(),
|
|
21
|
+
docs_url: str | None = "/docs",
|
|
22
|
+
docs_decorator = None,
|
|
23
|
+
servers: list[dict[str, Any]] | None = None,
|
|
24
|
+
urls_namespace: str | None = None,
|
|
25
|
+
csrf: bool = False,
|
|
26
|
+
auth: Sequence[Any]| NOT_SET_TYPE = NOT_SET,
|
|
27
|
+
throttle: BaseThrottle | list[BaseThrottle] | NOT_SET_TYPE = NOT_SET,
|
|
28
|
+
default_router: Router | None = None,
|
|
29
|
+
openapi_extra: dict[str, Any] | None = None
|
|
30
|
+
):
|
|
31
|
+
super().__init__(
|
|
32
|
+
title=title,
|
|
33
|
+
version=version,
|
|
34
|
+
description=description,
|
|
35
|
+
openapi_url=openapi_url,
|
|
36
|
+
docs=docs,
|
|
37
|
+
docs_url=docs_url,
|
|
38
|
+
docs_decorator=docs_decorator,
|
|
39
|
+
servers=servers,
|
|
40
|
+
urls_namespace=urls_namespace,
|
|
41
|
+
csrf=csrf,
|
|
42
|
+
auth=auth,
|
|
43
|
+
throttle=throttle,
|
|
44
|
+
default_router=default_router,
|
|
45
|
+
openapi_extra=openapi_extra,
|
|
46
|
+
renderer=ORJSONRenderer(),
|
|
47
|
+
parser=ORJSONParser(),
|
|
48
|
+
)
|
|
@@ -7,10 +7,10 @@ from ninja.orm import create_schema
|
|
|
7
7
|
from django.db import models
|
|
8
8
|
from django.http import HttpResponse, HttpRequest
|
|
9
9
|
from django.core.exceptions import ObjectDoesNotExist
|
|
10
|
-
from django.db.models.fields.related import OneToOneRel
|
|
11
10
|
from django.db.models.fields.related_descriptors import (
|
|
12
11
|
ReverseManyToOneDescriptor,
|
|
13
12
|
ReverseOneToOneDescriptor,
|
|
13
|
+
ManyToManyDescriptor,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
from .exceptions import SerializeError
|
|
@@ -46,6 +46,10 @@ class ModelSerializer(models.Model):
|
|
|
46
46
|
def has_custom_fields(self):
|
|
47
47
|
return self.has_custom_fields_create or self.has_custom_fields_update
|
|
48
48
|
|
|
49
|
+
@classmethod
|
|
50
|
+
def verbose_name_path_resolver(cls) -> str:
|
|
51
|
+
return "-".join(cls._meta.verbose_name_plural.split(" "))
|
|
52
|
+
|
|
49
53
|
def has_changed(self, field: str) -> bool:
|
|
50
54
|
"""
|
|
51
55
|
Check if a model field has changed
|
|
@@ -86,10 +90,14 @@ class ModelSerializer(models.Model):
|
|
|
86
90
|
reverse_rels = []
|
|
87
91
|
for f in cls.ReadSerializer.fields:
|
|
88
92
|
field_obj = getattr(cls, f)
|
|
93
|
+
if isinstance(field_obj, ManyToManyDescriptor):
|
|
94
|
+
reverse_rels.append(f)
|
|
95
|
+
continue
|
|
89
96
|
if isinstance(field_obj, ReverseManyToOneDescriptor):
|
|
90
97
|
reverse_rels.append(field_obj.field._related_name)
|
|
98
|
+
continue
|
|
91
99
|
if isinstance(field_obj, ReverseOneToOneDescriptor):
|
|
92
|
-
reverse_rels.append(
|
|
100
|
+
reverse_rels.append(field_obj.related.name)
|
|
93
101
|
return reverse_rels
|
|
94
102
|
|
|
95
103
|
@classmethod
|
|
@@ -98,14 +106,24 @@ class ModelSerializer(models.Model):
|
|
|
98
106
|
):
|
|
99
107
|
cls_f = []
|
|
100
108
|
for rel_f in obj.ReadSerializer.fields:
|
|
101
|
-
rel_f_obj = getattr(obj, rel_f)
|
|
109
|
+
rel_f_obj = getattr(obj, rel_f)
|
|
102
110
|
if (
|
|
103
|
-
isinstance(
|
|
104
|
-
|
|
111
|
+
isinstance(
|
|
112
|
+
rel_f_obj.field,
|
|
113
|
+
(
|
|
114
|
+
models.ForeignKey,
|
|
115
|
+
models.OneToOneField,
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
|
+
and rel_f_obj.field.related_model == cls
|
|
105
119
|
):
|
|
106
120
|
cls_f.append(rel_f)
|
|
107
121
|
obj.ReadSerializer.fields.remove(rel_f)
|
|
108
|
-
|
|
122
|
+
continue
|
|
123
|
+
if isinstance(rel_f_obj.field, models.ManyToManyField):
|
|
124
|
+
cls_f.append(rel_f)
|
|
125
|
+
obj.ReadSerializer.fields.remove(rel_f)
|
|
126
|
+
|
|
109
127
|
rel_schema = obj.generate_read_s(depth=0)
|
|
110
128
|
if rel_type == "many":
|
|
111
129
|
rel_schema = list[rel_schema]
|
|
@@ -124,13 +142,20 @@ class ModelSerializer(models.Model):
|
|
|
124
142
|
reverse_rels = []
|
|
125
143
|
for f in cls.ReadSerializer.fields:
|
|
126
144
|
field_obj = getattr(cls, f)
|
|
145
|
+
if isinstance(field_obj, ManyToManyDescriptor):
|
|
146
|
+
rel_obj: ModelSerializer = field_obj.field.related_model
|
|
147
|
+
if field_obj.reverse:
|
|
148
|
+
rel_obj: ModelSerializer = field_obj.field.model
|
|
149
|
+
rel_data = cls.get_reverse_relation_schema(rel_obj, "many", f)
|
|
150
|
+
reverse_rels.append(rel_data)
|
|
151
|
+
continue
|
|
127
152
|
if isinstance(field_obj, ReverseManyToOneDescriptor):
|
|
128
153
|
rel_obj: ModelSerializer = field_obj.field.model
|
|
129
154
|
rel_data = cls.get_reverse_relation_schema(rel_obj, "many", f)
|
|
130
155
|
reverse_rels.append(rel_data)
|
|
131
156
|
continue
|
|
132
157
|
if isinstance(field_obj, ReverseOneToOneDescriptor):
|
|
133
|
-
rel_obj: ModelSerializer =
|
|
158
|
+
rel_obj: ModelSerializer = field_obj.related.related_model
|
|
134
159
|
rel_data = cls.get_reverse_relation_schema(rel_obj, "one", f)
|
|
135
160
|
reverse_rels.append(rel_data)
|
|
136
161
|
continue
|
|
@@ -178,7 +203,7 @@ class ModelSerializer(models.Model):
|
|
|
178
203
|
field_obj = getattr(cls, k).related
|
|
179
204
|
if isinstance(v, dict) and (
|
|
180
205
|
isinstance(field_obj, models.ForeignKey)
|
|
181
|
-
or isinstance(field_obj,
|
|
206
|
+
or isinstance(field_obj, models.OneToOneField)
|
|
182
207
|
):
|
|
183
208
|
rel: ModelSerializer = await field_obj.related_model.get_object(
|
|
184
209
|
request, list(v.values())[0]
|
|
@@ -280,10 +305,10 @@ class ModelSerializer(models.Model):
|
|
|
280
305
|
for k, v in payload.items():
|
|
281
306
|
if v is not None:
|
|
282
307
|
setattr(obj, k, v)
|
|
283
|
-
|
|
284
|
-
await obj.custom_actions(payload)
|
|
308
|
+
await obj.custom_actions(customs)
|
|
285
309
|
await obj.asave()
|
|
286
|
-
|
|
310
|
+
updated_object = await cls.get_object(request, pk)
|
|
311
|
+
return await cls.read_s(request, updated_object)
|
|
287
312
|
|
|
288
313
|
@classmethod
|
|
289
314
|
async def delete_s(cls, request: HttpRequest, pk: int | str):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|