django-ninja-aio-crud 0.6.1__tar.gz → 0.6.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.
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/PKG-INFO +31 -2
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/README.md +30 -1
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/__init__.py +1 -1
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/auth.py +3 -13
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/exceptions.py +8 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/models.py +35 -20
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/api.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/parsers.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/renders.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/schemas.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/types.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/ninja_aio/views.py +0 -0
- {django_ninja_aio_crud-0.6.1 → django_ninja_aio_crud-0.6.2}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: django-ninja-aio-crud
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Django Ninja AIO CRUD - Rest Framework
|
|
5
5
|
Author: Giuseppe Casillo
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -100,7 +100,7 @@ class Foo(ModelSerializer):
|
|
|
100
100
|
fields = ["name", "bar"]
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
- 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
|
|
103
|
+
- 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.
|
|
104
104
|
|
|
105
105
|
```python
|
|
106
106
|
# models.py
|
|
@@ -184,6 +184,35 @@ class Foo(ModelSerializer):
|
|
|
184
184
|
excludes = ["id", "name"]
|
|
185
185
|
optionals = [("bar", str), ("active", bool)]
|
|
186
186
|
```
|
|
187
|
+
- If you want to add into ReadSerializer model properties you must define them as customs.
|
|
188
|
+
```python
|
|
189
|
+
# models.py
|
|
190
|
+
from django.db import models
|
|
191
|
+
from ninja_aio.models import ModelSerializer
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class Foo(ModelSerializer):
|
|
195
|
+
name = models.CharField(max_length=30)
|
|
196
|
+
bar = models.CharField(max_length=30, default="")
|
|
197
|
+
active = models.BooleanField(default=False)
|
|
198
|
+
|
|
199
|
+
@propetry
|
|
200
|
+
def full_name(self):
|
|
201
|
+
return f"{self.name} example_full_name"
|
|
202
|
+
|
|
203
|
+
class ReadSerializer:
|
|
204
|
+
excludes = ["bar"]
|
|
205
|
+
customs = [("full_name", str, "")]
|
|
206
|
+
|
|
207
|
+
class CreateSerializer:
|
|
208
|
+
fields = ["name"]
|
|
209
|
+
optionals = [("bar", str), ("active", bool)]
|
|
210
|
+
|
|
211
|
+
class UpdateSerializer:
|
|
212
|
+
excludes = ["id", "name"]
|
|
213
|
+
optionals = [("bar", str), ("active", bool)]
|
|
214
|
+
```
|
|
215
|
+
|
|
187
216
|
|
|
188
217
|
|
|
189
218
|
### APIViewSet
|
|
@@ -69,7 +69,7 @@ class Foo(ModelSerializer):
|
|
|
69
69
|
fields = ["name", "bar"]
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
- 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
|
|
72
|
+
- 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.
|
|
73
73
|
|
|
74
74
|
```python
|
|
75
75
|
# models.py
|
|
@@ -153,6 +153,35 @@ class Foo(ModelSerializer):
|
|
|
153
153
|
excludes = ["id", "name"]
|
|
154
154
|
optionals = [("bar", str), ("active", bool)]
|
|
155
155
|
```
|
|
156
|
+
- If you want to add into ReadSerializer model properties you must define them as customs.
|
|
157
|
+
```python
|
|
158
|
+
# models.py
|
|
159
|
+
from django.db import models
|
|
160
|
+
from ninja_aio.models import ModelSerializer
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class Foo(ModelSerializer):
|
|
164
|
+
name = models.CharField(max_length=30)
|
|
165
|
+
bar = models.CharField(max_length=30, default="")
|
|
166
|
+
active = models.BooleanField(default=False)
|
|
167
|
+
|
|
168
|
+
@propetry
|
|
169
|
+
def full_name(self):
|
|
170
|
+
return f"{self.name} example_full_name"
|
|
171
|
+
|
|
172
|
+
class ReadSerializer:
|
|
173
|
+
excludes = ["bar"]
|
|
174
|
+
customs = [("full_name", str, "")]
|
|
175
|
+
|
|
176
|
+
class CreateSerializer:
|
|
177
|
+
fields = ["name"]
|
|
178
|
+
optionals = [("bar", str), ("active", bool)]
|
|
179
|
+
|
|
180
|
+
class UpdateSerializer:
|
|
181
|
+
excludes = ["id", "name"]
|
|
182
|
+
optionals = [("bar", str), ("active", bool)]
|
|
183
|
+
```
|
|
184
|
+
|
|
156
185
|
|
|
157
186
|
|
|
158
187
|
### APIViewSet
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from joserfc import jwt, jwk
|
|
1
|
+
from joserfc import jwt, jwk
|
|
2
2
|
from django.http.request import HttpRequest
|
|
3
3
|
from ninja.security.http import HttpBearer
|
|
4
4
|
|
|
5
|
-
from .exceptions import AuthError
|
|
5
|
+
from .exceptions import AuthError
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class AsyncJwtBearer(HttpBearer):
|
|
@@ -16,15 +16,7 @@ class AsyncJwtBearer(HttpBearer):
|
|
|
16
16
|
|
|
17
17
|
def validate_claims(self, claims: jwt.Claims):
|
|
18
18
|
jwt_claims = self.get_claims()
|
|
19
|
-
|
|
20
|
-
try:
|
|
21
|
-
jwt_claims.validate(claims)
|
|
22
|
-
except (
|
|
23
|
-
errors.InvalidClaimError,
|
|
24
|
-
errors.MissingClaimError,
|
|
25
|
-
errors.ExpiredTokenError,
|
|
26
|
-
) as exc:
|
|
27
|
-
raise AuthError(**parse_jose_error(exc), status_code=401)
|
|
19
|
+
jwt_claims.validate(claims)
|
|
28
20
|
|
|
29
21
|
async def auth_handler(self, request: HttpRequest):
|
|
30
22
|
"""
|
|
@@ -35,8 +27,6 @@ class AsyncJwtBearer(HttpBearer):
|
|
|
35
27
|
async def authenticate(self, request: HttpRequest, token: str):
|
|
36
28
|
try:
|
|
37
29
|
self.dcd = jwt.decode(token, self.jwt_public, algorithms=self.algorithms)
|
|
38
|
-
except errors.BadSignatureError as exc:
|
|
39
|
-
raise AuthError(**parse_jose_error(exc), status_code=401)
|
|
40
30
|
except ValueError as exc:
|
|
41
31
|
raise AuthError(", ".join(exc.args), 401)
|
|
42
32
|
|
|
@@ -53,8 +53,16 @@ def _pydantic_validation_error(
|
|
|
53
53
|
return api.create_response(request, error.error, status=error.status_code)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
def _jose_error(
|
|
57
|
+
request: HttpRequest, exc: JoseError, api: type[NinjaAPI]
|
|
58
|
+
) -> HttpResponse:
|
|
59
|
+
error = BaseException(**parse_jose_error(exc), status_code=401)
|
|
60
|
+
return api.create_response(request, error.error, status=error.status_code)
|
|
61
|
+
|
|
62
|
+
|
|
56
63
|
def set_api_exception_handlers(api: type[NinjaAPI]) -> None:
|
|
57
64
|
api.add_exception_handler(BaseException, partial(_default_error, api=api))
|
|
65
|
+
api.add_exception_handler(JoseError, partial(_jose_error, api=api))
|
|
58
66
|
api.add_exception_handler(
|
|
59
67
|
ValidationError, partial(_pydantic_validation_error, api=api)
|
|
60
68
|
)
|
|
@@ -122,7 +122,10 @@ class ModelUtil:
|
|
|
122
122
|
try:
|
|
123
123
|
field_obj = getattr(self.model, k).field
|
|
124
124
|
except AttributeError:
|
|
125
|
-
|
|
125
|
+
try:
|
|
126
|
+
field_obj = getattr(self.model, k).related
|
|
127
|
+
except AttributeError:
|
|
128
|
+
pass
|
|
126
129
|
if isinstance(v, dict) and (
|
|
127
130
|
isinstance(field_obj, models.ForeignKey)
|
|
128
131
|
or isinstance(field_obj, models.OneToOneField)
|
|
@@ -196,6 +199,7 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
|
|
|
196
199
|
class ReadSerializer:
|
|
197
200
|
fields: list[str] = []
|
|
198
201
|
excludes: list[str] = []
|
|
202
|
+
customs: list[tuple[str, type, Any]] = []
|
|
199
203
|
|
|
200
204
|
class UpdateSerializer:
|
|
201
205
|
fields: list[str] = []
|
|
@@ -257,15 +261,15 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
|
|
|
257
261
|
case "Patch":
|
|
258
262
|
s_type = "update"
|
|
259
263
|
case "Out":
|
|
260
|
-
fields, reverse_rels, excludes = cls.get_schema_out_data()
|
|
261
|
-
if not fields and not reverse_rels and not excludes:
|
|
264
|
+
fields, reverse_rels, excludes, customs = cls.get_schema_out_data()
|
|
265
|
+
if not fields and not reverse_rels and not excludes and not customs:
|
|
262
266
|
return None
|
|
263
267
|
return create_schema(
|
|
264
268
|
model=cls,
|
|
265
269
|
name=f"{cls._meta.model_name}SchemaOut",
|
|
266
270
|
depth=depth,
|
|
267
271
|
fields=fields,
|
|
268
|
-
custom_fields=reverse_rels,
|
|
272
|
+
custom_fields=reverse_rels + customs,
|
|
269
273
|
exclude=excludes,
|
|
270
274
|
)
|
|
271
275
|
fields = cls.get_fields(s_type)
|
|
@@ -367,25 +371,36 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
|
|
|
367
371
|
reverse_rels = []
|
|
368
372
|
for f in cls.get_fields("read"):
|
|
369
373
|
field_obj = getattr(cls, f)
|
|
370
|
-
if isinstance(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
374
|
+
if isinstance(
|
|
375
|
+
field_obj,
|
|
376
|
+
(
|
|
377
|
+
ManyToManyDescriptor,
|
|
378
|
+
ReverseManyToOneDescriptor,
|
|
379
|
+
ReverseOneToOneDescriptor,
|
|
380
|
+
),
|
|
381
|
+
):
|
|
382
|
+
if isinstance(field_obj, ManyToManyDescriptor):
|
|
383
|
+
rel_obj: ModelSerializer = field_obj.field.related_model
|
|
384
|
+
if field_obj.reverse:
|
|
385
|
+
rel_obj = field_obj.field.model
|
|
386
|
+
rel_type = "many"
|
|
387
|
+
elif isinstance(field_obj, ReverseManyToOneDescriptor):
|
|
388
|
+
rel_obj = field_obj.field.model
|
|
389
|
+
rel_type = "many"
|
|
390
|
+
else: # ReverseOneToOneDescriptor
|
|
391
|
+
rel_obj = field_obj.related.related_model
|
|
392
|
+
rel_type = "one"
|
|
393
|
+
|
|
394
|
+
rel_data = cls.get_reverse_relation_schema(rel_obj, rel_type, f)
|
|
385
395
|
reverse_rels.append(rel_data)
|
|
386
396
|
continue
|
|
387
397
|
fields.append(f)
|
|
388
|
-
return
|
|
398
|
+
return (
|
|
399
|
+
fields,
|
|
400
|
+
reverse_rels,
|
|
401
|
+
cls.get_excluded_fields("read"),
|
|
402
|
+
cls.get_custom_fields("read"),
|
|
403
|
+
)
|
|
389
404
|
|
|
390
405
|
@classmethod
|
|
391
406
|
def is_custom(cls, field: str):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|