django-ninja-aio-crud 2.16.2__py3-none-any.whl → 2.18.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.
- django_ninja_aio_crud-2.18.0.dist-info/METADATA +425 -0
- {django_ninja_aio_crud-2.16.2.dist-info → django_ninja_aio_crud-2.18.0.dist-info}/RECORD +6 -6
- ninja_aio/__init__.py +1 -1
- ninja_aio/models/serializers.py +637 -74
- django_ninja_aio_crud-2.16.2.dist-info/METADATA +0 -379
- {django_ninja_aio_crud-2.16.2.dist-info → django_ninja_aio_crud-2.18.0.dist-info}/WHEEL +0 -0
- {django_ninja_aio_crud-2.16.2.dist-info → django_ninja_aio_crud-2.18.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-ninja-aio-crud
|
|
3
|
+
Version: 2.18.0
|
|
4
|
+
Summary: Django Ninja AIO CRUD - Rest Framework
|
|
5
|
+
Author: Giuseppe Casillo
|
|
6
|
+
Requires-Python: >=3.10, <3.15
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Topic :: Internet
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Classifier: Topic :: Software Development
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Framework :: Django
|
|
24
|
+
Classifier: Framework :: AsyncIO
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
26
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: django-ninja >=1.3.0, <1.6
|
|
29
|
+
Requires-Dist: joserfc >=1.0.0, <= 1.4.1
|
|
30
|
+
Requires-Dist: orjson >= 3.10.7, <= 3.11.5
|
|
31
|
+
Requires-Dist: coverage ; extra == "test"
|
|
32
|
+
Project-URL: Documentation, https://django-ninja-aio.com
|
|
33
|
+
Project-URL: Repository, https://github.com/caspel26/django-ninja-aio-crud
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="https://raw.githubusercontent.com/caspel26/django-ninja-aio-crud/main/docs/images/logo.png" alt="django-ninja-aio-crud" width="120">
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<h1 align="center">django-ninja-aio-crud</h1>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<strong>Async CRUD framework for Django Ninja</strong><br>
|
|
44
|
+
Automatic schema generation · Filtering · Pagination · Auth · M2M management
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<a href="https://github.com/caspel26/django-ninja-aio-crud/actions/workflows/coverage.yml"><img src="https://github.com/caspel26/django-ninja-aio-crud/actions/workflows/coverage.yml/badge.svg" alt="Tests"></a>
|
|
49
|
+
<a href="https://sonarcloud.io/summary/new_code?id=caspel26_django-ninja-aio-crud"><img src="https://sonarcloud.io/api/project_badges/measure?project=caspel26_django-ninja-aio-crud&metric=alert_status" alt="Quality Gate Status"></a>
|
|
50
|
+
<a href="https://codecov.io/gh/caspel26/django-ninja-aio-crud/"><img src="https://codecov.io/gh/caspel26/django-ninja-aio-crud/graph/badge.svg?token=DZ5WDT3S20" alt="codecov"></a>
|
|
51
|
+
<a href="https://pypi.org/project/django-ninja-aio-crud/"><img src="https://img.shields.io/pypi/v/django-ninja-aio-crud?color=g&logo=pypi&logoColor=white" alt="PyPI - Version"></a>
|
|
52
|
+
<a href="LICENSE"><img src="https://img.shields.io/pypi/l/django-ninja-aio-crud" alt="PyPI - License"></a>
|
|
53
|
+
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<a href="https://django-ninja-aio.com">Documentation</a> ·
|
|
58
|
+
<a href="https://pypi.org/project/django-ninja-aio-crud/">PyPI</a> ·
|
|
59
|
+
<a href="https://github.com/caspel26/ninja-aio-blog-example">Example Project</a> ·
|
|
60
|
+
<a href="https://github.com/caspel26/django-ninja-aio-crud/issues">Issues</a>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
| | Feature | Description |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| **Meta-driven Serializer** | Dynamic schemas | Generate CRUD schemas for existing Django models without changing base classes |
|
|
70
|
+
| **Async CRUD ViewSets** | Full operations | Create, list, retrieve, update, delete — all async |
|
|
71
|
+
| **Auto Schemas** | Pydantic generation | Automatic read/create/update schemas from `ModelSerializer` |
|
|
72
|
+
| **Dynamic Query Params** | Runtime schemas | Built with `pydantic.create_model` for flexible filtering |
|
|
73
|
+
| **Per-method Auth** | Granular control | `auth`, `get_auth`, `post_auth`, etc. |
|
|
74
|
+
| **Async Pagination** | Customizable | Fully async, pluggable pagination classes |
|
|
75
|
+
| **M2M Relations** | Add/remove/list | Endpoints via `M2MRelationSchema` with filtering support |
|
|
76
|
+
| **Reverse Relations** | Nested serialization | Automatic handling of reverse FK and M2M |
|
|
77
|
+
| **Lifecycle Hooks** | Extensible | `before_save`, `after_save`, `custom_actions`, `on_delete`, and more |
|
|
78
|
+
| **Schema Validators** | Pydantic validators | `@field_validator` and `@model_validator` on serializer classes |
|
|
79
|
+
| **ORJSON Renderer** | Performance | Built-in fast JSON rendering via `NinjaAIO` |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
### Option A: Meta-driven Serializer (existing models)
|
|
86
|
+
|
|
87
|
+
Use this if you already have Django models and don't want to change their base class.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from ninja_aio.models import serializers
|
|
91
|
+
from ninja_aio.views import APIViewSet
|
|
92
|
+
from ninja_aio import NinjaAIO
|
|
93
|
+
from . import models
|
|
94
|
+
|
|
95
|
+
class BookSerializer(serializers.Serializer):
|
|
96
|
+
class Meta:
|
|
97
|
+
model = models.Book
|
|
98
|
+
schema_in = serializers.SchemaModelConfig(fields=["title", "published"])
|
|
99
|
+
schema_out = serializers.SchemaModelConfig(fields=["id", "title", "published"])
|
|
100
|
+
schema_update = serializers.SchemaModelConfig(
|
|
101
|
+
optionals=[("title", str), ("published", bool)]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
api = NinjaAIO()
|
|
105
|
+
|
|
106
|
+
@api.viewset(models.Book)
|
|
107
|
+
class BookViewSet(APIViewSet):
|
|
108
|
+
serializer_class = BookSerializer
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Option B: ModelSerializer (new projects)
|
|
112
|
+
|
|
113
|
+
Define models with built-in serialization for minimal boilerplate.
|
|
114
|
+
|
|
115
|
+
**models.py**
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from django.db import models
|
|
119
|
+
from ninja_aio.models import ModelSerializer
|
|
120
|
+
|
|
121
|
+
class Book(ModelSerializer):
|
|
122
|
+
title = models.CharField(max_length=120)
|
|
123
|
+
published = models.BooleanField(default=True)
|
|
124
|
+
|
|
125
|
+
class ReadSerializer:
|
|
126
|
+
fields = ["id", "title", "published"]
|
|
127
|
+
|
|
128
|
+
class CreateSerializer:
|
|
129
|
+
fields = ["title", "published"]
|
|
130
|
+
|
|
131
|
+
class UpdateSerializer:
|
|
132
|
+
optionals = [("title", str), ("published", bool)]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**views.py**
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from ninja_aio import NinjaAIO
|
|
139
|
+
from ninja_aio.views import APIViewSet
|
|
140
|
+
from .models import Book
|
|
141
|
+
|
|
142
|
+
api = NinjaAIO()
|
|
143
|
+
|
|
144
|
+
@api.viewset(Book)
|
|
145
|
+
class BookViewSet(APIViewSet):
|
|
146
|
+
pass
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
> Visit `/docs` — CRUD endpoints ready.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Query Filtering
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
@api.viewset(Book)
|
|
157
|
+
class BookViewSet(APIViewSet):
|
|
158
|
+
query_params = {"published": (bool, None), "title": (str, None)}
|
|
159
|
+
|
|
160
|
+
async def query_params_handler(self, queryset, filters):
|
|
161
|
+
if filters.get("published") is not None:
|
|
162
|
+
queryset = queryset.filter(published=filters["published"])
|
|
163
|
+
if filters.get("title"):
|
|
164
|
+
queryset = queryset.filter(title__icontains=filters["title"])
|
|
165
|
+
return queryset
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
GET /book/?published=true&title=python
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Many-to-Many Relations
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from ninja_aio.schemas import M2MRelationSchema
|
|
178
|
+
|
|
179
|
+
class Tag(ModelSerializer):
|
|
180
|
+
name = models.CharField(max_length=50)
|
|
181
|
+
class ReadSerializer:
|
|
182
|
+
fields = ["id", "name"]
|
|
183
|
+
|
|
184
|
+
class Article(ModelSerializer):
|
|
185
|
+
title = models.CharField(max_length=120)
|
|
186
|
+
tags = models.ManyToManyField(Tag, related_name="articles")
|
|
187
|
+
class ReadSerializer:
|
|
188
|
+
fields = ["id", "title", "tags"]
|
|
189
|
+
|
|
190
|
+
@api.viewset(Article)
|
|
191
|
+
class ArticleViewSet(APIViewSet):
|
|
192
|
+
m2m_relations = [
|
|
193
|
+
M2MRelationSchema(
|
|
194
|
+
model=Tag,
|
|
195
|
+
related_name="tags",
|
|
196
|
+
filters={"name": (str, "")}
|
|
197
|
+
)
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
async def tags_query_params_handler(self, queryset, filters):
|
|
201
|
+
n = filters.get("name")
|
|
202
|
+
if n:
|
|
203
|
+
queryset = queryset.filter(name__icontains=n)
|
|
204
|
+
return queryset
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Endpoints:**
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
GET /article/{pk}/tag?name=dev
|
|
211
|
+
POST /article/{pk}/tag/ body: {"add": [1, 2], "remove": [3]}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Authentication (JWT)
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from ninja_aio.auth import AsyncJwtBearer
|
|
220
|
+
from joserfc import jwk
|
|
221
|
+
|
|
222
|
+
class JWTAuth(AsyncJwtBearer):
|
|
223
|
+
jwt_public = jwk.RSAKey.import_key("-----BEGIN PUBLIC KEY----- ...")
|
|
224
|
+
jwt_alg = "RS256"
|
|
225
|
+
claims = {"sub": {"essential": True}}
|
|
226
|
+
|
|
227
|
+
async def auth_handler(self, request):
|
|
228
|
+
book_id = self.dcd.claims.get("sub")
|
|
229
|
+
return await Book.objects.aget(id=book_id)
|
|
230
|
+
|
|
231
|
+
@api.viewset(Book)
|
|
232
|
+
class SecureBookViewSet(APIViewSet):
|
|
233
|
+
auth = [JWTAuth()]
|
|
234
|
+
get_auth = None # list/retrieve remain public
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Lifecycle Hooks
|
|
240
|
+
|
|
241
|
+
Available on every save/delete cycle:
|
|
242
|
+
|
|
243
|
+
| Hook | When |
|
|
244
|
+
|---|---|
|
|
245
|
+
| `on_create_before_save` | Before first save |
|
|
246
|
+
| `on_create_after_save` | After first save |
|
|
247
|
+
| `before_save` | Before any save |
|
|
248
|
+
| `after_save` | After any save |
|
|
249
|
+
| `on_delete` | After deletion |
|
|
250
|
+
| `custom_actions(payload)` | Create/update custom field logic |
|
|
251
|
+
| `post_create()` | After create commit |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Custom Endpoints
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from ninja_aio.decorators import api_get
|
|
259
|
+
|
|
260
|
+
@api.viewset(Book)
|
|
261
|
+
class BookViewSet(APIViewSet):
|
|
262
|
+
@api_get("/stats/")
|
|
263
|
+
async def stats(self, request):
|
|
264
|
+
total = await Book.objects.acount()
|
|
265
|
+
return {"total": total}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Pagination
|
|
271
|
+
|
|
272
|
+
Default: `PageNumberPagination`. Override per ViewSet:
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
from ninja.pagination import PageNumberPagination
|
|
276
|
+
|
|
277
|
+
class LargePagination(PageNumberPagination):
|
|
278
|
+
page_size = 50
|
|
279
|
+
max_page_size = 200
|
|
280
|
+
|
|
281
|
+
@api.viewset(Book)
|
|
282
|
+
class BookViewSet(APIViewSet):
|
|
283
|
+
pagination_class = LargePagination
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Schema Validators
|
|
289
|
+
|
|
290
|
+
Add Pydantic `@field_validator` and `@model_validator` directly on serializer classes for input validation.
|
|
291
|
+
|
|
292
|
+
### ModelSerializer
|
|
293
|
+
|
|
294
|
+
Declare validators on inner serializer classes:
|
|
295
|
+
|
|
296
|
+
```python
|
|
297
|
+
from django.db import models
|
|
298
|
+
from pydantic import field_validator, model_validator
|
|
299
|
+
from ninja_aio.models import ModelSerializer
|
|
300
|
+
|
|
301
|
+
class Book(ModelSerializer):
|
|
302
|
+
title = models.CharField(max_length=120)
|
|
303
|
+
description = models.TextField(blank=True)
|
|
304
|
+
|
|
305
|
+
class CreateSerializer:
|
|
306
|
+
fields = ["title", "description"]
|
|
307
|
+
|
|
308
|
+
@field_validator("title")
|
|
309
|
+
@classmethod
|
|
310
|
+
def validate_title_min_length(cls, v):
|
|
311
|
+
if len(v) < 3:
|
|
312
|
+
raise ValueError("Title must be at least 3 characters")
|
|
313
|
+
return v
|
|
314
|
+
|
|
315
|
+
class UpdateSerializer:
|
|
316
|
+
optionals = [("title", str), ("description", str)]
|
|
317
|
+
|
|
318
|
+
@field_validator("title")
|
|
319
|
+
@classmethod
|
|
320
|
+
def validate_title_not_empty(cls, v):
|
|
321
|
+
if v is not None and len(v.strip()) == 0:
|
|
322
|
+
raise ValueError("Title cannot be blank")
|
|
323
|
+
return v
|
|
324
|
+
|
|
325
|
+
class ReadSerializer:
|
|
326
|
+
fields = ["id", "title", "description"]
|
|
327
|
+
|
|
328
|
+
@model_validator(mode="after")
|
|
329
|
+
def enrich_output(self):
|
|
330
|
+
# Transform or enrich the output schema
|
|
331
|
+
return self
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Meta-driven Serializer
|
|
335
|
+
|
|
336
|
+
Use dedicated `{Type}Validators` inner classes:
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
from pydantic import field_validator, model_validator
|
|
340
|
+
from ninja_aio.models import serializers
|
|
341
|
+
from . import models
|
|
342
|
+
|
|
343
|
+
class BookSerializer(serializers.Serializer):
|
|
344
|
+
class Meta:
|
|
345
|
+
model = models.Book
|
|
346
|
+
schema_in = serializers.SchemaModelConfig(fields=["title", "description"])
|
|
347
|
+
schema_out = serializers.SchemaModelConfig(fields=["id", "title", "description"])
|
|
348
|
+
schema_update = serializers.SchemaModelConfig(
|
|
349
|
+
optionals=[("title", str), ("description", str)]
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
class CreateValidators:
|
|
353
|
+
@field_validator("title")
|
|
354
|
+
@classmethod
|
|
355
|
+
def validate_title_min_length(cls, v):
|
|
356
|
+
if len(v) < 3:
|
|
357
|
+
raise ValueError("Title must be at least 3 characters")
|
|
358
|
+
return v
|
|
359
|
+
|
|
360
|
+
class UpdateValidators:
|
|
361
|
+
@field_validator("title")
|
|
362
|
+
@classmethod
|
|
363
|
+
def validate_title_not_empty(cls, v):
|
|
364
|
+
if v is not None and len(v.strip()) == 0:
|
|
365
|
+
raise ValueError("Title cannot be blank")
|
|
366
|
+
return v
|
|
367
|
+
|
|
368
|
+
class ReadValidators:
|
|
369
|
+
@model_validator(mode="after")
|
|
370
|
+
def enrich_output(self):
|
|
371
|
+
return self
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Validator class mapping:**
|
|
375
|
+
|
|
376
|
+
| Schema type | ModelSerializer | Serializer (Meta-driven) |
|
|
377
|
+
|---|---|---|
|
|
378
|
+
| Create | `CreateSerializer` | `CreateValidators` |
|
|
379
|
+
| Update | `UpdateSerializer` | `UpdateValidators` |
|
|
380
|
+
| Read | `ReadSerializer` | `ReadValidators` |
|
|
381
|
+
| Detail | `DetailSerializer` | `DetailValidators` |
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Disable Operations
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
@api.viewset(Book)
|
|
389
|
+
class ReadOnlyBookViewSet(APIViewSet):
|
|
390
|
+
disable = ["update", "delete"]
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Performance Tips
|
|
396
|
+
|
|
397
|
+
- Use `queryset_request` classmethod to `select_related` / `prefetch_related`
|
|
398
|
+
- Index frequently filtered fields
|
|
399
|
+
- Keep pagination enabled for large datasets
|
|
400
|
+
- Limit slices (`queryset = queryset[:1000]`) for heavy searches
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Contributing
|
|
405
|
+
|
|
406
|
+
1. Fork the repository
|
|
407
|
+
2. Create a feature branch
|
|
408
|
+
3. Add tests for your changes
|
|
409
|
+
4. Run lint: `ruff check .`
|
|
410
|
+
5. Open a Pull Request
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Support
|
|
415
|
+
|
|
416
|
+
If you find this project useful, consider giving it a star or supporting development:
|
|
417
|
+
|
|
418
|
+
<a href="https://buymeacoffee.com/caspel26"><img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black" alt="Buy me a coffee"></a>
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT License. See [LICENSE](LICENSE).
|
|
425
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ninja_aio/__init__.py,sha256=
|
|
1
|
+
ninja_aio/__init__.py,sha256=CezrF0WOFMCLNAybIgP0uAtNTsUMEiOezULFLq3iluY,120
|
|
2
2
|
ninja_aio/api.py,sha256=tuC7vdvn7s1GkCnSFy9Kn1zv0glZfYptRQVvo8ZRtGQ,2429
|
|
3
3
|
ninja_aio/auth.py,sha256=f4yk45fLi36Qctu0A0zgHTFedb9yk3ewq5rOMpoPYIE,9035
|
|
4
4
|
ninja_aio/exceptions.py,sha256=w8QWmVlg88iJvBrNODSDBHSsy8nNpwngaCGWRnkXoPo,3899
|
|
@@ -14,7 +14,7 @@ ninja_aio/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
14
14
|
ninja_aio/helpers/api.py,sha256=va_HvZVBFm1KxwQhH4u09U4F1JS5JrQuRpRmPTHJt7w,21326
|
|
15
15
|
ninja_aio/helpers/query.py,sha256=Lqv4nrWYr543tC5K-SEcBottLID8cb83aDc26i2Wxj4,5053
|
|
16
16
|
ninja_aio/models/__init__.py,sha256=L3UQnQAlKoI3F7jinadL-Nn55hkPvnSRPYW0JtnbWFo,114
|
|
17
|
-
ninja_aio/models/serializers.py,sha256=
|
|
17
|
+
ninja_aio/models/serializers.py,sha256=Obw6HCLMU9iTvAtuoGFXB2gtRELtR3g1nhn23U9McrM,60376
|
|
18
18
|
ninja_aio/models/utils.py,sha256=lAXtc3YY7_n4f0jIacX4DSXhUOzMy7y5MsBnInNxtfk,32874
|
|
19
19
|
ninja_aio/schemas/__init__.py,sha256=dHILiYBKMb51lDcyQdiXRw_0nzqM7Lu81UX2hv7kEfo,837
|
|
20
20
|
ninja_aio/schemas/api.py,sha256=dGUpJXR1iAf93QNR4kYj1uqIkTjiMfXultCotY6GtaQ,361
|
|
@@ -24,7 +24,7 @@ ninja_aio/schemas/helpers.py,sha256=CpubwNXsZHtu8jddliyQybF1epwZ-GO60vHIuF5AR1Y,
|
|
|
24
24
|
ninja_aio/views/__init__.py,sha256=DEzjWA6y3WF0V10nNF8eEurLNEodgxKzyFd09AqVp3s,148
|
|
25
25
|
ninja_aio/views/api.py,sha256=AAqkj0xT8J3PmJvsbluZ33cfrmrXJHiV9ARe2BqnfQ8,22492
|
|
26
26
|
ninja_aio/views/mixins.py,sha256=Zl6J8gbVagwT85bzDuKyJTk3iFxxFgX0YgYkjiUxZGg,17040
|
|
27
|
-
django_ninja_aio_crud-2.
|
|
28
|
-
django_ninja_aio_crud-2.
|
|
29
|
-
django_ninja_aio_crud-2.
|
|
30
|
-
django_ninja_aio_crud-2.
|
|
27
|
+
django_ninja_aio_crud-2.18.0.dist-info/licenses/LICENSE,sha256=yrDAYcm0gRp_Qyzo3GQa4BjYjWRkAhGC8QRva__RYq0,1073
|
|
28
|
+
django_ninja_aio_crud-2.18.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
29
|
+
django_ninja_aio_crud-2.18.0.dist-info/METADATA,sha256=2R1JT9MbqKfuAb05If2Ic1U-Cx6l_uTcXLPKHIyod5Q,12911
|
|
30
|
+
django_ninja_aio_crud-2.18.0.dist-info/RECORD,,
|