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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-ninja-aio-crud
3
- Version: 0.6.1
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(custom fields are only available for Create and Update serializers).
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(custom fields are only available for Create and Update serializers).
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,6 +1,6 @@
1
1
  """Django Ninja AIO CRUD - Rest Framework"""
2
2
 
3
- __version__ = "0.6.1"
3
+ __version__ = "0.6.2"
4
4
 
5
5
  from .api import NinjaAIO
6
6
 
@@ -1,8 +1,8 @@
1
- from joserfc import jwt, jwk, errors
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, parse_jose_error
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
- field_obj = getattr(self.model, k).related
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(field_obj, ManyToManyDescriptor):
371
- rel_obj: ModelSerializer = field_obj.field.related_model
372
- if field_obj.reverse:
373
- rel_obj: ModelSerializer = field_obj.field.model
374
- rel_data = cls.get_reverse_relation_schema(rel_obj, "many", f)
375
- reverse_rels.append(rel_data)
376
- continue
377
- if isinstance(field_obj, ReverseManyToOneDescriptor):
378
- rel_obj: ModelSerializer = field_obj.field.model
379
- rel_data = cls.get_reverse_relation_schema(rel_obj, "many", f)
380
- reverse_rels.append(rel_data)
381
- continue
382
- if isinstance(field_obj, ReverseOneToOneDescriptor):
383
- rel_obj: ModelSerializer = field_obj.related.related_model
384
- rel_data = cls.get_reverse_relation_schema(rel_obj, "one", f)
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 fields, reverse_rels, cls.get_excluded_fields("read")
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):