django-ninja-aio-crud 0.6.2__py3-none-any.whl → 0.6.3__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.6.2
3
+ Version: 0.6.3
4
4
  Summary: Django Ninja AIO CRUD - Rest Framework
5
5
  Author: Giuseppe Casillo
6
6
  Requires-Python: >=3.10
@@ -196,7 +196,7 @@ class Foo(ModelSerializer):
196
196
  bar = models.CharField(max_length=30, default="")
197
197
  active = models.BooleanField(default=False)
198
198
 
199
- @propetry
199
+ @property
200
200
  def full_name(self):
201
201
  return f"{self.name} example_full_name"
202
202
 
@@ -1,13 +1,12 @@
1
- ninja_aio/__init__.py,sha256=fj_imNMQNt3s9V2z1MaTVCq27ZeyFxCD555vG2F80d8,119
1
+ ninja_aio/__init__.py,sha256=ZONk9sZ6Zj3LZKMblnnSP8auyeIk3DqIEMqQnMuIX60,119
2
2
  ninja_aio/api.py,sha256=Fe6l3YCy7MW5TY4-Lbl80CFuK2NT2Y7tHfmqPk6Mqak,1735
3
3
  ninja_aio/auth.py,sha256=fKboioU4sezPukKJukIwiboxml_KV7irhCH3vGYt5pU,1008
4
4
  ninja_aio/exceptions.py,sha256=gPnZX1Do2GXudbU8wDYkwhO70Qj0ZNrIJJ2UXRs9vYk,2241
5
- ninja_aio/models.py,sha256=58Uk24f2IQYDdnGq1vXp8HqmCwDYeSkZtbiQ9JOQEXc,15504
5
+ ninja_aio/models.py,sha256=p8X_G2WVlygDE8UEJ7O2fajauJYu1d_pgcvFPDkHRwc,15638
6
6
  ninja_aio/parsers.py,sha256=e_4lGCPV7zs-HTqtdJTc8yQD2KPAn9njbL8nF_Mmgkc,153
7
7
  ninja_aio/renders.py,sha256=mHeKNJtmDhZmgFpS9B6SPn5uZFcyVXrsoMhr149LeW8,1555
8
8
  ninja_aio/schemas.py,sha256=EgRkfhnzZqwGvdBmqlZixMtMcoD1ZxV_qzJ3fmaAy20,113
9
9
  ninja_aio/types.py,sha256=EHznS-6KWLwSX5hLeXbAi7qHWla09_rGeQraiLpH-aY,491
10
- ninja_aio/views.py,sha256=z820mKzfbvh9SZ4cALQVKMfc64kx74t8xWGWaUBzHfs,9270
11
- django_ninja_aio_crud-0.6.2.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
12
- django_ninja_aio_crud-0.6.2.dist-info/METADATA,sha256=QFGhtfwohjs0YQG1K6ysZpHQEYtfM0BTJaopwqaFmGQ,13740
13
- django_ninja_aio_crud-0.6.2.dist-info/RECORD,,
10
+ django_ninja_aio_crud-0.6.3.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
11
+ django_ninja_aio_crud-0.6.3.dist-info/METADATA,sha256=26XLVzdo5EKej1jre04eUxspawzraIVI4LbRm8Qqymc,13740
12
+ django_ninja_aio_crud-0.6.3.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.6.2"
3
+ __version__ = "0.6.3"
4
4
 
5
5
  from .api import NinjaAIO
6
6
 
ninja_aio/models.py CHANGED
@@ -51,13 +51,14 @@ class ModelUtil:
51
51
  pk: int | str = None,
52
52
  filters: dict = None,
53
53
  getters: dict = None,
54
+ with_qs_request=True,
54
55
  ):
55
56
  get_q = {self.model_pk_name: pk} if pk is not None else {}
56
57
  if getters:
57
58
  get_q |= getters
58
59
 
59
60
  obj_qs = self.model.objects.select_related()
60
- if isinstance(self.model, ModelSerializerMeta):
61
+ if isinstance(self.model, ModelSerializerMeta) and with_qs_request:
61
62
  obj_qs = await self.model.queryset_request(request)
62
63
 
63
64
  obj_qs = obj_qs.prefetch_related(*self.get_reverse_relations())
@@ -108,7 +109,9 @@ class ModelUtil:
108
109
  raise SerializeError({k: ". ".join(exc.args)}, 400)
109
110
  if isinstance(field_obj, models.ForeignKey):
110
111
  rel_util = ModelUtil(field_obj.related_model)
111
- rel: ModelSerializer = await rel_util.get_object(request, v)
112
+ rel: ModelSerializer = await rel_util.get_object(
113
+ request, v, with_qs_request=False
114
+ )
112
115
  payload |= {k: rel}
113
116
  new_payload = {
114
117
  k: v for k, v in payload.items() if k not in (customs.keys() or optionals)
@@ -132,7 +135,7 @@ class ModelUtil:
132
135
  ):
133
136
  rel_util = ModelUtil(field_obj.related_model)
134
137
  rel: ModelSerializer = await rel_util.get_object(
135
- request, list(v.values())[0]
138
+ request, list(v.values())[0], with_qs_request=False
136
139
  )
137
140
  if isinstance(field_obj, models.ForeignKey):
138
141
  for rel_k, rel_v in v.items():
ninja_aio/views.py DELETED
@@ -1,271 +0,0 @@
1
- from typing import List
2
-
3
- from ninja import NinjaAPI, Router, Schema, Path, Query
4
- from ninja.constants import NOT_SET
5
- from ninja.pagination import paginate, AsyncPaginationBase, PageNumberPagination
6
- from django.http import HttpRequest
7
- from django.db.models import Model, QuerySet
8
- from pydantic import create_model
9
-
10
- from .models import ModelSerializer, ModelUtil
11
- from .schemas import GenericMessageSchema
12
- from .types import ModelSerializerMeta, VIEW_TYPES
13
-
14
- ERROR_CODES = frozenset({400, 401, 404, 428})
15
-
16
-
17
- class APIView:
18
- api: NinjaAPI
19
- router_tag: str
20
- api_route_path: str
21
- auths: list | None = NOT_SET
22
-
23
- def __init__(self) -> None:
24
- self.router = Router(tags=[self.router_tag])
25
- self.error_codes = ERROR_CODES
26
-
27
- def views(self):
28
- """
29
- Override this method to add your custom views. For example:
30
- @self.router.get(some_path, response=some_schema)
31
- async def some_method(request, *args, **kwargs):
32
- pass
33
-
34
- You can add multilple views just doing:
35
-
36
- @self.router.get(some_path, response=some_schema)
37
- async def some_method(request, *args, **kwargs):
38
- pass
39
-
40
- @self.router.post(some_path, response=some_schema)
41
- async def some_method(request, *args, **kwargs):
42
- pass
43
-
44
- If you provided a list of auths you can chose which of your views
45
- should be authenticated:
46
-
47
- AUTHENTICATED VIEW:
48
-
49
- @self.router.get(some_path, response=some_schema, auth=self.auths)
50
- async def some_method(request, *args, **kwargs):
51
- pass
52
-
53
- NOT AUTHENTICATED VIEW:
54
-
55
- @self.router.post(some_path, response=some_schema)
56
- async def some_method(request, *args, **kwargs):
57
- pass
58
- """
59
-
60
- def add_views(self):
61
- self.views()
62
- return self.router
63
-
64
- def add_views_to_route(self):
65
- return self.api.add_router(f"{self.api_route_path}/", self.add_views())
66
-
67
-
68
- class APIViewSet:
69
- model: ModelSerializer | Model
70
- api: NinjaAPI
71
- schema_in: Schema | None = None
72
- schema_out: Schema | None = None
73
- schema_update: Schema | None = None
74
- auths: list | None = NOT_SET
75
- pagination_class: type[AsyncPaginationBase] = PageNumberPagination
76
- query_params: dict[str, tuple[type, ...]] = {}
77
- disable: list[type[VIEW_TYPES]] = []
78
-
79
- def __init__(self) -> None:
80
- self.error_codes = ERROR_CODES
81
- self.model_util = ModelUtil(self.model)
82
- self.schema_out, self.schema_in, self.schema_update = self.get_schemas()
83
- self.path_schema = self._generate_path_schema()
84
- self.filters_schema = self._generate_filters_schema()
85
- self.router_tag = self.model_util.model_name.capitalize()
86
- self.router = Router(tags=[self.router_tag])
87
- self.path = "/"
88
- self.path_retrieve = f"{{{self.model_util.model_pk_name}}}/"
89
-
90
- @property
91
- def _crud_views(self):
92
- """
93
- key: view type (create, list, retrieve, update, delete or all)
94
- value: tuple with schema and view method
95
- """
96
- return {
97
- "create": (self.schema_in, self.create_view),
98
- "list": (self.schema_out, self.list_view),
99
- "retrieve": (self.schema_out, self.retrieve_view),
100
- "update": (self.schema_update, self.update_view),
101
- "delete": (None, self.delete_view),
102
- }
103
-
104
- def _generate_schema(self, fields: dict, name: str) -> Schema:
105
- return create_model(f"{self.model_util.model_name}{name}", **fields)
106
-
107
- def _generate_path_schema(self):
108
- return self._generate_schema(
109
- {self.model_util.model_pk_name: (int | str, ...)}, "PathSchema"
110
- )
111
-
112
- def _generate_filters_schema(self):
113
- return self._generate_schema(self.query_params, "FiltersSchema")
114
-
115
- def _get_pk(self, data: Schema):
116
- return data.model_dump()[self.model_util.model_pk_name]
117
-
118
- def get_schemas(self):
119
- if isinstance(self.model, ModelSerializerMeta):
120
- return (
121
- self.model.generate_read_s(),
122
- self.model.generate_create_s(),
123
- self.model.generate_update_s(),
124
- )
125
- return self.schema_out, self.schema_in, self.schema_update
126
-
127
- async def query_params_handler(
128
- self, queryset: QuerySet[ModelSerializer], filters: dict
129
- ):
130
- """
131
- Override this method to handle request query params making queries to the database
132
- based on filters or any other logic. This method should return a queryset. filters
133
- are given already dumped by the schema.
134
- """
135
- return queryset
136
-
137
- def create_view(self):
138
- @self.router.post(
139
- self.path,
140
- auth=self.auths,
141
- response={201: self.schema_out, self.error_codes: GenericMessageSchema},
142
- )
143
- async def create(request: HttpRequest, data: self.schema_in):
144
- return 201, await self.model_util.create_s(request, data, self.schema_out)
145
-
146
- create.__name__ = f"create_{self.model_util.model_name}"
147
- return create
148
-
149
- def list_view(self):
150
- @self.router.get(
151
- self.path,
152
- auth=self.auths,
153
- response={
154
- 200: List[self.schema_out],
155
- self.error_codes: GenericMessageSchema,
156
- },
157
- )
158
- @paginate(self.pagination_class)
159
- async def list(
160
- request: HttpRequest, filters: Query[self.filters_schema] = None
161
- ):
162
- qs = self.model.objects.select_related()
163
- if isinstance(self.model, ModelSerializerMeta):
164
- qs = await self.model.queryset_request(request)
165
- rels = self.model_util.get_reverse_relations()
166
- if len(rels) > 0:
167
- qs = qs.prefetch_related(*rels)
168
- if filters is not None:
169
- qs = await self.query_params_handler(qs, filters.model_dump())
170
- objs = [
171
- await self.model_util.read_s(request, obj, self.schema_out)
172
- async for obj in qs.all()
173
- ]
174
- return objs
175
-
176
- list.__name__ = f"list_{self.model_util.verbose_name_view_resolver()}"
177
- return list
178
-
179
- def retrieve_view(self):
180
- @self.router.get(
181
- self.path_retrieve,
182
- auth=self.auths,
183
- response={200: self.schema_out, self.error_codes: GenericMessageSchema},
184
- )
185
- async def retrieve(request: HttpRequest, pk: Path[self.path_schema]):
186
- obj = await self.model_util.get_object(request, self._get_pk(pk))
187
- return await self.model_util.read_s(request, obj, self.schema_out)
188
-
189
- retrieve.__name__ = f"retrieve_{self.model_util.model_name}"
190
- return retrieve
191
-
192
- def update_view(self):
193
- @self.router.patch(
194
- self.path_retrieve,
195
- auth=self.auths,
196
- response={200: self.schema_out, self.error_codes: GenericMessageSchema},
197
- )
198
- async def update(
199
- request: HttpRequest, data: self.schema_update, pk: Path[self.path_schema]
200
- ):
201
- return await self.model_util.update_s(
202
- request, data, self._get_pk(pk), self.schema_out
203
- )
204
-
205
- update.__name__ = f"update_{self.model_util.model_name}"
206
- return update
207
-
208
- def delete_view(self):
209
- @self.router.delete(
210
- self.path_retrieve,
211
- auth=self.auths,
212
- response={204: None, self.error_codes: GenericMessageSchema},
213
- )
214
- async def delete(request: HttpRequest, pk: Path[self.path_schema]):
215
- return 204, await self.model_util.delete_s(request, self._get_pk(pk))
216
-
217
- delete.__name__ = f"delete_{self.model_util.model_name}"
218
- return delete
219
-
220
- def views(self):
221
- """
222
- Override this method to add your custom views. For example:
223
- @self.router.get(some_path, response=some_schema)
224
- async def some_method(request, *args, **kwargs):
225
- pass
226
-
227
- You can add multilple views just doing:
228
-
229
- @self.router.get(some_path, response=some_schema)
230
- async def some_method(request, *args, **kwargs):
231
- pass
232
-
233
- @self.router.post(some_path, response=some_schema)
234
- async def some_method(request, *args, **kwargs):
235
- pass
236
-
237
- If you provided a list of auths you can chose which of your views
238
- should be authenticated:
239
-
240
- AUTHENTICATED VIEW:
241
-
242
- @self.router.get(some_path, response=some_schema, auth=self.auths)
243
- async def some_method(request, *args, **kwargs):
244
- pass
245
-
246
- NOT AUTHENTICATED VIEW:
247
-
248
- @self.router.post(some_path, response=some_schema)
249
- async def some_method(request, *args, **kwargs):
250
- pass
251
- """
252
-
253
- def add_views(self):
254
- if "all" in self.disable:
255
- self.views()
256
- return self.router
257
-
258
- for views_type, (schema, view) in self._crud_views.items():
259
- if views_type not in self.disable and (
260
- schema is not None or views_type == "delete"
261
- ):
262
- view()
263
-
264
- self.views()
265
- return self.router
266
-
267
- def add_views_to_route(self):
268
- return self.api.add_router(
269
- f"{self.model_util.verbose_name_path_resolver()}/",
270
- self.add_views(),
271
- )