django-ninja-aio-crud 0.4.0__py3-none-any.whl → 0.5.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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-ninja-aio-crud
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Django Ninja AIO CRUD - Rest Framework
5
5
  Author: Giuseppe Casillo
6
6
  Requires-Python: >=3.10
@@ -153,6 +153,32 @@ class Foo(ModelSerializer):
153
153
  optionals = [[("bar", str), ("active", bool)]
154
154
  ```
155
155
 
156
+ - 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").
157
+
158
+ ```python
159
+ # models.py
160
+ from django.db import models
161
+ from ninja_aio.models import ModelSerializer
162
+
163
+
164
+ class Foo(ModelSerializer):
165
+ name = models.CharField(max_length=30)
166
+ bar = models.CharField(max_length=30, default="")
167
+ active = models.BooleanField(default=False)
168
+
169
+ class ReadSerializer:
170
+ excludes = ["bar"]
171
+
172
+ class CreateSerializer:
173
+ fields = ["name"]
174
+ optionals = [("bar", str), ("active", bool)]
175
+
176
+ class UpdateSerializer:
177
+ excludes = ["id", "name"]
178
+ optionals = [[("bar", str), ("active", bool)]
179
+ ```
180
+
181
+
156
182
  ### APIViewSet
157
183
 
158
184
  - 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.
@@ -161,8 +187,6 @@ class Foo(ModelSerializer):
161
187
  # views.py
162
188
  from ninja_aio import NinjaAIO
163
189
  from ninja_aio.views import APIViewSet
164
- from ninja_aio.parsers import ORJSONParser
165
- from ninja_aio.renders import ORJSONRender
166
190
 
167
191
  from .models import Foo
168
192
 
@@ -184,8 +208,6 @@ FooAPI().add_views_to_route()
184
208
  from ninja import Schema
185
209
  from ninja_aio import NinjaAIO
186
210
  from ninja_aio.views import APIViewSet
187
- from ninja_aio.parsers import ORJSONParser
188
- from ninja_aio.renders import ORJSONRender
189
211
 
190
212
  from .models import Foo
191
213
 
@@ -211,6 +233,27 @@ class FooAPI(APIViewSet):
211
233
  return 200, {sum: data.n1 + data.n2}
212
234
 
213
235
 
236
+ FooAPI().add_views_to_route()
237
+ ```
238
+
239
+ - 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.
240
+
241
+ ```python
242
+ # views.py
243
+ from ninja_aio import NinjaAIO
244
+ from ninja_aio.views import APIViewSet
245
+
246
+ from .models import Foo
247
+
248
+ api = NinjaAIO()
249
+
250
+
251
+ class FooAPI(APIViewSet):
252
+ model = Foo
253
+ api = api
254
+ disable = ["retrieve", "update"]
255
+
256
+
214
257
  FooAPI().add_views_to_route()
215
258
  ```
216
259
 
@@ -223,8 +266,6 @@ FooAPI().add_views_to_route()
223
266
  from ninja import Schema
224
267
  from ninja_aio import NinjaAIO
225
268
  from ninja_aio.views import APIView
226
- from ninja_aio.parsers import ORJSONParser
227
- from ninja_aio.renders import ORJSONRender
228
269
 
229
270
  api = NinjaAIO()
230
271
 
@@ -294,8 +335,6 @@ class Foo(ModelSerializer):
294
335
  # views.py
295
336
  from ninja_aio import NinjaAIO
296
337
  from ninja_aio.views import APIViewSet
297
- from ninja_aio.parsers import ORJSONParser
298
- from ninja_aio.renders import ORJSONRender
299
338
 
300
339
  from .models import Foo, Bar
301
340
 
@@ -361,8 +400,6 @@ class CustomJWTBearer(AsyncJWTBearer):
361
400
  from ninja import Schema
362
401
  from ninja_aio import NinjaAIO
363
402
  from ninja_aio.views import APIViewSet, APIView
364
- from ninja_aio.parsers import ORJSONParser
365
- from ninja_aio.renders import ORJSONRender
366
403
 
367
404
  from .models import Foo
368
405
 
@@ -0,0 +1,13 @@
1
+ ninja_aio/__init__.py,sha256=ZragxlHPdmlSQb8pX6GdLzlHSdO-6qs4EelxyzrSMGw,119
2
+ ninja_aio/api.py,sha256=Fe6l3YCy7MW5TY4-Lbl80CFuK2NT2Y7tHfmqPk6Mqak,1735
3
+ ninja_aio/auth.py,sha256=3Pr8llYoCN59ZH3J_2qWmzjXxsy-rpQzXrVfwLfY25Q,1299
4
+ ninja_aio/exceptions.py,sha256=LP9GZpDk1fYMRRgGHSAstcCvgu5uSDLg8PPDANlZGTs,1008
5
+ ninja_aio/models.py,sha256=wCEQfzU3Q96rMwbkqBMjuaPipILRoX2eorId1hfsiR4,14569
6
+ ninja_aio/parsers.py,sha256=e_4lGCPV7zs-HTqtdJTc8yQD2KPAn9njbL8nF_Mmgkc,153
7
+ ninja_aio/renders.py,sha256=mHeKNJtmDhZmgFpS9B6SPn5uZFcyVXrsoMhr149LeW8,1555
8
+ ninja_aio/schemas.py,sha256=EgRkfhnzZqwGvdBmqlZixMtMcoD1ZxV_qzJ3fmaAy20,113
9
+ ninja_aio/types.py,sha256=EHznS-6KWLwSX5hLeXbAi7qHWla09_rGeQraiLpH-aY,491
10
+ ninja_aio/views.py,sha256=p0wWVMw1TRtdCSHKfIWHPINGn3rkGWFPsRwMyg4HUOs,8121
11
+ django_ninja_aio_crud-0.5.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
12
+ django_ninja_aio_crud-0.5.0.dist-info/METADATA,sha256=FdZKHgHjgaZqqrv9BNB801Q1lHjSlYaMFUA-cBA_SQs,11573
13
+ django_ninja_aio_crud-0.5.0.dist-info/RECORD,,
ninja_aio/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Django Ninja AIO CRUD - Rest Framework"""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.5.0"
4
4
 
5
5
  from .api import NinjaAIO
6
6
 
ninja_aio/models.py CHANGED
@@ -5,7 +5,7 @@ from ninja.schema import Schema
5
5
  from ninja.orm import create_schema
6
6
 
7
7
  from django.db import models
8
- from django.http import HttpResponse, HttpRequest
8
+ from django.http import HttpRequest
9
9
  from django.core.exceptions import ObjectDoesNotExist
10
10
  from django.db.models.fields.related_descriptors import (
11
11
  ReverseManyToOneDescriptor,
@@ -14,7 +14,7 @@ from django.db.models.fields.related_descriptors import (
14
14
  )
15
15
 
16
16
  from .exceptions import SerializeError
17
- from .types import S_TYPES, REL_TYPES, F_TYPES, ModelSerializerMeta
17
+ from .types import S_TYPES, REL_TYPES, F_TYPES, SCHEMA_TYPES, ModelSerializerMeta
18
18
 
19
19
 
20
20
  class ModelUtil:
@@ -24,12 +24,15 @@ class ModelUtil:
24
24
  @property
25
25
  def serializable_fields(self):
26
26
  if isinstance(self.model, ModelSerializerMeta):
27
- return self.model.ReadSerializer.fields
27
+ return self.model.get_fields("read")
28
28
  return [field.name for field in self.model._meta.get_fields()]
29
29
 
30
30
  def verbose_name_path_resolver(self) -> str:
31
31
  return "-".join(self.model._meta.verbose_name_plural.split(" "))
32
32
 
33
+ def verbose_name_view_resolver(self) -> str:
34
+ return self.model._meta.verbose_name_plural.replace(" ", "")
35
+
33
36
  async def get_object(self, request: HttpRequest, pk: int | str):
34
37
  q = {self.model._meta.pk.attname: pk}
35
38
  obj_qs = self.model.objects.select_related()
@@ -121,7 +124,7 @@ class ModelUtil:
121
124
  if isinstance(self.model, ModelSerializerMeta):
122
125
  await obj.custom_actions(customs)
123
126
  await obj.post_create()
124
- return 201, await self.read_s(request, obj, obj_schema)
127
+ return await self.read_s(request, obj, obj_schema)
125
128
 
126
129
  async def read_s(
127
130
  self,
@@ -150,7 +153,7 @@ class ModelUtil:
150
153
  async def delete_s(self, request: HttpRequest, pk: int | str):
151
154
  obj = await self.get_object(request, pk)
152
155
  await obj.adelete()
153
- return HttpResponse(status=204)
156
+ return None
154
157
 
155
158
 
156
159
  class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
@@ -160,15 +163,18 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
160
163
  class CreateSerializer:
161
164
  fields: list[str] = []
162
165
  customs: list[tuple[str, type, Any]] = []
163
- optionals: list[str] = []
166
+ optionals: list[tuple[str, type]] = []
167
+ excludes: list[str] = []
164
168
 
165
169
  class ReadSerializer:
166
170
  fields: list[str] = []
171
+ excludes: list[str] = []
167
172
 
168
173
  class UpdateSerializer:
169
174
  fields: list[str] = []
170
175
  customs: list[tuple[str, type, Any]] = []
171
- optionals: list[str] = []
176
+ optionals: list[tuple[str, type]] = []
177
+ excludes: list[str] = []
172
178
 
173
179
  @property
174
180
  def has_custom_fields_create(self):
@@ -195,24 +201,61 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
195
201
  return self.has_optional_fields_create or self.has_optional_fields_update
196
202
 
197
203
  @classmethod
198
- def _get_special_fields(cls, s_type: type[S_TYPES], f_type: type[F_TYPES]):
199
- try:
200
- match s_type:
201
- case "create":
202
- fields = getattr(cls.CreateSerializer, f_type)
203
- case "update":
204
- fields = getattr(cls.UpdateSerializer, f_type)
205
- except AttributeError:
206
- return []
204
+ def _get_fields(cls, s_type: type[S_TYPES], f_type: type[F_TYPES]):
205
+ match s_type:
206
+ case "create":
207
+ fields = getattr(cls.CreateSerializer, f_type, [])
208
+ case "update":
209
+ fields = getattr(cls.UpdateSerializer, f_type, [])
210
+ case "read":
211
+ fields = getattr(cls.ReadSerializer, f_type, [])
207
212
  return fields
208
213
 
209
214
  @classmethod
210
215
  def _is_special_field(
211
216
  cls, s_type: type[S_TYPES], field: str, f_type: type[F_TYPES]
212
217
  ):
213
- special_fields = cls._get_special_fields(s_type, f_type)
218
+ special_fields = cls._get_fields(s_type, f_type)
214
219
  return any(field in special_f for special_f in special_fields)
215
220
 
221
+ @classmethod
222
+ def _generate_model_schema(
223
+ cls,
224
+ schema_type: type[SCHEMA_TYPES],
225
+ depth: int = None,
226
+ ) -> Schema:
227
+ match schema_type:
228
+ case "In":
229
+ s_type = "create"
230
+ case "Patch":
231
+ s_type = "update"
232
+ case "Out":
233
+ fields, reverse_rels, excludes = cls.get_schema_out_data()
234
+ if not fields and not reverse_rels and not excludes:
235
+ return None
236
+ return create_schema(
237
+ model=cls,
238
+ name=f"{cls._meta.model_name}SchemaOut",
239
+ depth=depth,
240
+ fields=fields,
241
+ custom_fields=reverse_rels,
242
+ exclude=excludes,
243
+ )
244
+ fields = cls.get_fields(s_type)
245
+ customs = cls.get_custom_fields(s_type) + cls.get_optional_fields(s_type)
246
+ excludes = cls.get_excluded_fields(s_type)
247
+ return (
248
+ create_schema(
249
+ model=cls,
250
+ name=f"{cls._meta.model_name}Schema{schema_type}",
251
+ fields=fields,
252
+ custom_fields=customs,
253
+ exclude=excludes,
254
+ )
255
+ if fields or customs or excludes
256
+ else None
257
+ )
258
+
216
259
  @classmethod
217
260
  def verbose_name_path_resolver(cls) -> str:
218
261
  return "-".join(cls._meta.verbose_name_plural.split(" "))
@@ -292,7 +335,7 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
292
335
  def get_schema_out_data(cls):
293
336
  fields = []
294
337
  reverse_rels = []
295
- for f in cls.ReadSerializer.fields:
338
+ for f in cls.get_fields("read"):
296
339
  field_obj = getattr(cls, f)
297
340
  if isinstance(field_obj, ManyToManyDescriptor):
298
341
  rel_obj: ModelSerializer = field_obj.field.related_model
@@ -312,7 +355,7 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
312
355
  reverse_rels.append(rel_data)
313
356
  continue
314
357
  fields.append(f)
315
- return fields, reverse_rels
358
+ return fields, reverse_rels, cls.get_excluded_fields("read")
316
359
 
317
360
  @classmethod
318
361
  def is_custom(cls, field: str):
@@ -328,49 +371,31 @@ class ModelSerializer(models.Model, metaclass=ModelSerializerMeta):
328
371
 
329
372
  @classmethod
330
373
  def get_custom_fields(cls, s_type: type[S_TYPES]):
331
- return cls._get_special_fields(s_type, "customs")
374
+ return cls._get_fields(s_type, "customs")
332
375
 
333
376
  @classmethod
334
377
  def get_optional_fields(cls, s_type: type[S_TYPES]):
335
378
  return [
336
379
  (field, field_type, None)
337
- for field, field_type in cls._get_special_fields(s_type, "optionals")
380
+ for field, field_type in cls._get_fields(s_type, "optionals")
338
381
  ]
382
+
383
+ @classmethod
384
+ def get_excluded_fields(cls, s_type: type[S_TYPES]):
385
+ return cls._get_fields(s_type, "excludes")
386
+
387
+ @classmethod
388
+ def get_fields(cls, s_type: type[S_TYPES]):
389
+ return cls._get_fields(s_type, "fields")
339
390
 
340
391
  @classmethod
341
392
  def generate_read_s(cls, depth: int = 1) -> Schema:
342
- fields, reverse_rels = cls.get_schema_out_data()
343
- customs = [custom for custom in reverse_rels]
344
- return create_schema(
345
- model=cls,
346
- name=f"{cls._meta.model_name}SchemaOut",
347
- depth=depth,
348
- fields=fields,
349
- custom_fields=customs,
350
- )
393
+ return cls._generate_model_schema("Out", depth)
351
394
 
352
395
  @classmethod
353
396
  def generate_create_s(cls) -> Schema:
354
- fields = getattr(cls.CreateSerializer, "fields", []) + [
355
- field[0] for field in cls.get_optional_fields("create")
356
- ]
357
- customs = cls.get_custom_fields("create") + cls.get_optional_fields("create")
358
- return create_schema(
359
- model=cls,
360
- name=f"{cls._meta.model_name}SchemaIn",
361
- fields=fields,
362
- custom_fields=customs,
363
- )
397
+ return cls._generate_model_schema("In")
364
398
 
365
399
  @classmethod
366
400
  def generate_update_s(cls) -> Schema:
367
- fields = getattr(cls.UpdateSerializer, "fields", []) + [
368
- field[0] for field in cls.get_optional_fields("update")
369
- ]
370
- customs = cls.get_custom_fields("update") + cls.get_optional_fields("update")
371
- return create_schema(
372
- model=cls,
373
- name=f"{cls._meta.model_name}SchemaPatch",
374
- fields=fields,
375
- custom_fields=customs,
376
- )
401
+ return cls._generate_model_schema("Patch")
ninja_aio/types.py CHANGED
@@ -2,10 +2,11 @@ from typing import Literal
2
2
 
3
3
  from django.db.models import Model
4
4
 
5
- S_TYPES = Literal["create", "update"]
5
+ S_TYPES = Literal["read", "create", "update"]
6
6
  REL_TYPES = Literal["many", "one"]
7
- F_TYPES = Literal["customs", "optionals"]
8
-
7
+ F_TYPES = Literal["fields", "customs", "optionals", "excludes"]
8
+ SCHEMA_TYPES = Literal["In", "Out", "Patch"]
9
+ VIEW_TYPES = Literal["list", "retrieve", "create", "update", "delete", "all"]
9
10
 
10
11
  class ModelSerializerType(type):
11
12
  def __repr__(self):
ninja_aio/views.py CHANGED
@@ -1,14 +1,15 @@
1
1
  from typing import List
2
2
 
3
- from ninja import NinjaAPI, Router, Schema
3
+ from ninja import NinjaAPI, Router, Schema, Path
4
4
  from ninja.constants import NOT_SET
5
5
  from ninja.pagination import paginate, AsyncPaginationBase, PageNumberPagination
6
6
  from django.http import HttpRequest
7
7
  from django.db.models import Model
8
+ from pydantic import create_model
8
9
 
9
10
  from .models import ModelSerializer, ModelUtil
10
11
  from .schemas import GenericMessageSchema
11
- from .types import ModelSerializerMeta
12
+ from .types import ModelSerializerMeta, VIEW_TYPES
12
13
 
13
14
  ERROR_CODES = frozenset({400, 401, 404, 428})
14
15
 
@@ -55,7 +56,6 @@ class APIView:
55
56
  async def some_method(request, *args, **kwargs):
56
57
  pass
57
58
  """
58
- pass
59
59
 
60
60
  def add_views(self):
61
61
  self.views()
@@ -73,23 +73,45 @@ class APIViewSet:
73
73
  schema_update: Schema | None = None
74
74
  auths: list | None = NOT_SET
75
75
  pagination_class: type[AsyncPaginationBase] = PageNumberPagination
76
+ disable: list[type[VIEW_TYPES]] = []
76
77
 
77
78
  def __init__(self) -> None:
78
79
  self.router = Router(tags=[self.model._meta.model_name.capitalize()])
79
80
  self.path = "/"
80
- self.path_retrieve = f"{self.model._meta.pk.attname}/"
81
+ self.path_retrieve = f"{{{self.model._meta.pk.attname}}}/"
81
82
  self.error_codes = ERROR_CODES
82
83
  self.model_util = ModelUtil(self.model)
83
- self.schema_out, self.schema_update, self.schema_in = self.get_schemas()
84
+ self.schema_out, self.schema_in, self.schema_update = self.get_schemas()
85
+ self.path_schema = self._create_path_schema()
86
+
87
+ @property
88
+ def _crud_views(self):
89
+ """
90
+ key: view type (create, list, retrieve, update, delete or all)
91
+ value: tuple with schema and view method
92
+ """
93
+ return {
94
+ "create": (self.schema_in, self.create_view),
95
+ "list": (self.schema_out, self.list_view),
96
+ "retrieve": (self.schema_out, self.retrieve_view),
97
+ "update": (self.schema_update, self.update_view),
98
+ "delete": (None, self.delete_view),
99
+ }
100
+
101
+ def _create_path_schema(self):
102
+ fields = {
103
+ self.model._meta.pk.attname: (str | int , ...),
104
+ }
105
+ return create_model(f"{self.model._meta.model_name}PathSchema", **fields)
84
106
 
85
107
  def get_schemas(self):
86
108
  if isinstance(self.model, ModelSerializerMeta):
87
109
  return (
88
110
  self.model.generate_read_s(),
89
- self.model.generate_update_s(),
90
111
  self.model.generate_create_s(),
112
+ self.model.generate_update_s(),
91
113
  )
92
- return self.schema_out, self.schema_update, self.schema_in
114
+ return self.schema_out, self.schema_in, self.schema_update
93
115
 
94
116
  def create_view(self):
95
117
  @self.router.post(
@@ -98,9 +120,10 @@ class APIViewSet:
98
120
  response={201: self.schema_out, self.error_codes: GenericMessageSchema},
99
121
  )
100
122
  async def create(request: HttpRequest, data: self.schema_in):
101
- return await self.model_util.create_s(request, data, self.schema_out)
123
+ return 201, await self.model_util.create_s(request, data, self.schema_out)
102
124
 
103
125
  create.__name__ = f"create_{self.model._meta.model_name}"
126
+ return create
104
127
 
105
128
  def list_view(self):
106
129
  @self.router.get(
@@ -117,7 +140,6 @@ class APIViewSet:
117
140
  if isinstance(self.model, ModelSerializerMeta):
118
141
  qs = await self.model.queryset_request(request)
119
142
  rels = self.model_util.get_reverse_relations()
120
- print(rels)
121
143
  if len(rels) > 0:
122
144
  qs = qs.prefetch_related(*rels)
123
145
  objs = [
@@ -126,7 +148,8 @@ class APIViewSet:
126
148
  ]
127
149
  return objs
128
150
 
129
- list.__name__ = f"list_{self.model._meta.verbose_name_plural}"
151
+ list.__name__ = f"list_{self.model_util.verbose_name_view_resolver()}"
152
+ return list
130
153
 
131
154
  def retrieve_view(self):
132
155
  @self.router.get(
@@ -134,11 +157,12 @@ class APIViewSet:
134
157
  auth=self.auths,
135
158
  response={200: self.schema_out, self.error_codes: GenericMessageSchema},
136
159
  )
137
- async def retrieve(request: HttpRequest, pk: int | str):
160
+ async def retrieve(request: HttpRequest, pk: Path[self.path_schema]):
138
161
  obj = await self.model_util.get_object(request, pk)
139
162
  return await self.model_util.read_s(request, obj, self.schema_out)
140
163
 
141
164
  retrieve.__name__ = f"retrieve_{self.model._meta.model_name}"
165
+ return retrieve
142
166
 
143
167
  def update_view(self):
144
168
  @self.router.patch(
@@ -146,10 +170,11 @@ class APIViewSet:
146
170
  auth=self.auths,
147
171
  response={200: self.schema_out, self.error_codes: GenericMessageSchema},
148
172
  )
149
- async def update(request: HttpRequest, data: self.schema_update, pk: int | str):
173
+ async def update(request: HttpRequest, data: self.schema_update, pk: Path[self.path_schema]):
150
174
  return await self.model_util.update_s(request, data, pk, self.schema_out)
151
175
 
152
176
  update.__name__ = f"update_{self.model._meta.model_name}"
177
+ return update
153
178
 
154
179
  def delete_view(self):
155
180
  @self.router.delete(
@@ -157,10 +182,11 @@ class APIViewSet:
157
182
  auth=self.auths,
158
183
  response={204: None, self.error_codes: GenericMessageSchema},
159
184
  )
160
- async def delete(request: HttpRequest, pk: int | str):
161
- return await self.model_util.delete_s(request, pk)
185
+ async def delete(request: HttpRequest, pk: Path[self.path_schema]):
186
+ return 204, await self.model_util.delete_s(request, pk)
162
187
 
163
188
  delete.__name__ = f"delete_{self.model._meta.model_name}"
189
+ return delete
164
190
 
165
191
  def views(self):
166
192
  """
@@ -194,14 +220,18 @@ class APIViewSet:
194
220
  async def some_method(request, *args, **kwargs):
195
221
  pass
196
222
  """
197
- pass
198
223
 
199
224
  def add_views(self):
200
- self.create_view()
201
- self.list_view()
202
- self.retrieve_view()
203
- self.update_view()
204
- self.delete_view()
225
+ if "all" in self.disable:
226
+ self.views()
227
+ return self.router
228
+
229
+ for views_type, (schema, view) in self._crud_views.items():
230
+ if views_type not in self.disable and (
231
+ schema is not None or views_type == "delete"
232
+ ):
233
+ view()
234
+
205
235
  self.views()
206
236
  return self.router
207
237
 
@@ -1,13 +0,0 @@
1
- ninja_aio/__init__.py,sha256=GPvxFosuQ4fZ9LpbRClXqv8e7BecmVUtj2nvbJyalus,119
2
- ninja_aio/api.py,sha256=Fe6l3YCy7MW5TY4-Lbl80CFuK2NT2Y7tHfmqPk6Mqak,1735
3
- ninja_aio/auth.py,sha256=3Pr8llYoCN59ZH3J_2qWmzjXxsy-rpQzXrVfwLfY25Q,1299
4
- ninja_aio/exceptions.py,sha256=LP9GZpDk1fYMRRgGHSAstcCvgu5uSDLg8PPDANlZGTs,1008
5
- ninja_aio/models.py,sha256=mIZofuGOsRATYQki7GIuz50OQWfMes41cvOOAAonQA0,13768
6
- ninja_aio/parsers.py,sha256=e_4lGCPV7zs-HTqtdJTc8yQD2KPAn9njbL8nF_Mmgkc,153
7
- ninja_aio/renders.py,sha256=mHeKNJtmDhZmgFpS9B6SPn5uZFcyVXrsoMhr149LeW8,1555
8
- ninja_aio/schemas.py,sha256=EgRkfhnzZqwGvdBmqlZixMtMcoD1ZxV_qzJ3fmaAy20,113
9
- ninja_aio/types.py,sha256=ZhFqRDP5g2A2er3izx36QjrYJxL_jgusbH7w7mVHNrk,339
10
- ninja_aio/views.py,sha256=IT6rTCcjXcVYrCi4_uEwnGOGXeWlIB4ZuyXJp8Fsqqc,6971
11
- django_ninja_aio_crud-0.4.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
12
- django_ninja_aio_crud-0.4.0.dist-info/METADATA,sha256=0yQr4CWufJ7ZtXuhpTOchKQ-yOzG7o-wTaymDV0Tqvc,10832
13
- django_ninja_aio_crud-0.4.0.dist-info/RECORD,,