django-ninja-aio-crud 2.15.1__tar.gz → 2.16.0__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.
Potentially problematic release.
This version of django-ninja-aio-crud might be problematic. Click here for more details.
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/PKG-INFO +1 -1
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/__init__.py +1 -1
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/helpers/api.py +11 -1
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/schemas/helpers.py +8 -2
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/helpers/test_many_to_many_api.py +155 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.github/dependabot.yml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.github/workflows/coverage.yml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.github/workflows/docs.yml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.github/workflows/publish.yml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.gitignore +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.pre-commit-config.yaml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/LICENSE +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/README.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/CNAME +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/authentication.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/models/model_serializer.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/models/model_util.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/models/serializers.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/pagination.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/renderers/orjson_renderer.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/views/api_view.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/views/api_view_set.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/views/decorators.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/views/mixins.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/auth.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/contributing.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/extra.css +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-create-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-delete-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-list-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-retrieve-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/images/index/foo-index-update-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/installation.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/quick_start.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/images/bar-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/images/favicon.ico +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/images/foo-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/images/logo.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/images/model_util/foo-reverse-relations-swagger.png +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/index.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/release_notes.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/requirements.txt +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/tutorial/authentication.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/tutorial/crud.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/tutorial/filtering.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/tutorial/model.md +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/main.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/mkdocs.yml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/api.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/auth.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/decorators/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/decorators/operations.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/decorators/views.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/exceptions.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/factory/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/factory/operations.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/helpers/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/helpers/query.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/models/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/models/serializers.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/models/utils.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/parsers.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/renders.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/schemas/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/schemas/api.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/schemas/filters.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/schemas/generics.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/types.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/views/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/views/api.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/views/mixins.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/pyproject.toml +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/requirements.dev.txt +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/run-local-coverage.sh +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/test_decorators.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/test_exceptions_api.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/test_renderer_parser.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/generics/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/generics/literals.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/generics/models.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/generics/request.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/generics/views.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/helpers/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/models/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/models/test_model_util.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/models/test_models_extra.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_app/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_app/models.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_app/schema.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_app/serializers.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_app/views.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_auth.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_decorators.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_exceptions.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_query_util.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_serializers.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/test_settings.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/views/__init__.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/views/test_views.py +0 -0
- {django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/views/test_viewset.py +0 -0
|
@@ -359,6 +359,7 @@ class ManyToManyAPI:
|
|
|
359
359
|
filters_schema,
|
|
360
360
|
append_slash: bool,
|
|
361
361
|
verbose_name_plural: str,
|
|
362
|
+
decorators: list,
|
|
362
363
|
):
|
|
363
364
|
@self.router.get(
|
|
364
365
|
self._get_api_path(rel_path, append_slash=append_slash),
|
|
@@ -373,6 +374,7 @@ class ManyToManyAPI:
|
|
|
373
374
|
@decorate_view(
|
|
374
375
|
unique_view(f"get_{self.related_model_util.model_name}_{rel_path}"),
|
|
375
376
|
paginate(self.pagination_class),
|
|
377
|
+
*decorators,
|
|
376
378
|
)
|
|
377
379
|
async def get_related(
|
|
378
380
|
request: HttpRequest,
|
|
@@ -407,6 +409,7 @@ class ManyToManyAPI:
|
|
|
407
409
|
m2m_add: bool,
|
|
408
410
|
m2m_remove: bool,
|
|
409
411
|
verbose_name_plural: str,
|
|
412
|
+
decorators: list,
|
|
410
413
|
):
|
|
411
414
|
action, schema_in = self._resolve_action_schema(m2m_add, m2m_remove)
|
|
412
415
|
plural = verbose_name_plural
|
|
@@ -422,7 +425,10 @@ class ManyToManyAPI:
|
|
|
422
425
|
summary=summary,
|
|
423
426
|
description=summary,
|
|
424
427
|
)
|
|
425
|
-
@
|
|
428
|
+
@decorate_view(
|
|
429
|
+
unique_view(f"manage_{self.related_model_util.model_name}_{rel_path}"),
|
|
430
|
+
*decorators,
|
|
431
|
+
)
|
|
426
432
|
async def manage_related(
|
|
427
433
|
request: HttpRequest,
|
|
428
434
|
pk: Path[self.path_schema], # type: ignore
|
|
@@ -483,6 +489,8 @@ class ManyToManyAPI:
|
|
|
483
489
|
relation.verbose_name_plural
|
|
484
490
|
or rel_util.model._meta.verbose_name_plural.capitalize()
|
|
485
491
|
)
|
|
492
|
+
get_decorators = relation.get_decorators or []
|
|
493
|
+
post_decorators = relation.post_decorators or []
|
|
486
494
|
|
|
487
495
|
if m2m_get:
|
|
488
496
|
self._register_get_relation_view(
|
|
@@ -494,6 +502,7 @@ class ManyToManyAPI:
|
|
|
494
502
|
filters_schema=filters_schema,
|
|
495
503
|
append_slash=append_slash,
|
|
496
504
|
verbose_name_plural=verbose_name_plural,
|
|
505
|
+
decorators=get_decorators,
|
|
497
506
|
)
|
|
498
507
|
|
|
499
508
|
if m2m_add or m2m_remove:
|
|
@@ -505,6 +514,7 @@ class ManyToManyAPI:
|
|
|
505
514
|
m2m_add=m2m_add,
|
|
506
515
|
m2m_remove=m2m_remove,
|
|
507
516
|
verbose_name_plural=verbose_name_plural,
|
|
517
|
+
decorators=post_decorators,
|
|
508
518
|
)
|
|
509
519
|
|
|
510
520
|
def _add_views(self):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional, Type
|
|
1
|
+
from typing import Callable, List, Optional, Type
|
|
2
2
|
|
|
3
3
|
from ninja import Schema
|
|
4
4
|
from ninja_aio.types import ModelSerializerMeta, SerializerMeta
|
|
@@ -46,7 +46,11 @@ class M2MRelationSchema(BaseModel):
|
|
|
46
46
|
Whether to append a trailing slash to the generated GET endpoint path. Defaults to False for backward compatibility.
|
|
47
47
|
verbose_name_plural (str | None):
|
|
48
48
|
Optional human-readable plural name for the related model, used in documentation and responses.
|
|
49
|
-
|
|
49
|
+
get_decorators (List | None):
|
|
50
|
+
Optional list of decorators to apply to the GET endpoint.
|
|
51
|
+
post_decorators (List | None):
|
|
52
|
+
Optional list of decorators to apply to the POST (add/remove) endpoints.
|
|
53
|
+
|
|
50
54
|
Validation:
|
|
51
55
|
- If `model` is not a ModelSerializerMeta, `related_schema` is required.
|
|
52
56
|
- When `model` is a ModelSerializerMeta and `related_schema` is not provided, it will be
|
|
@@ -72,6 +76,8 @@ class M2MRelationSchema(BaseModel):
|
|
|
72
76
|
serializer_class: Optional[SerializerMeta] = None
|
|
73
77
|
append_slash: bool = False
|
|
74
78
|
verbose_name_plural: Optional[str] = None
|
|
79
|
+
get_decorators: Optional[List[Callable]] = []
|
|
80
|
+
post_decorators: Optional[List[Callable]] = []
|
|
75
81
|
|
|
76
82
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
77
83
|
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/helpers/test_many_to_many_api.py
RENAMED
|
@@ -280,3 +280,158 @@ class M2MRelationSchemaValidationTestCase(TestCase):
|
|
|
280
280
|
serializer_class=TestModelReverseManyToManySerializer,
|
|
281
281
|
)
|
|
282
282
|
self.assertEqual(schema.related_schema, CustomSchema)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# Decorator tracking for tests
|
|
286
|
+
_decorator_calls = {"get": 0, "post": 0}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def track_get_decorator(func):
|
|
290
|
+
"""Decorator that tracks GET endpoint calls."""
|
|
291
|
+
from functools import wraps
|
|
292
|
+
|
|
293
|
+
@wraps(func)
|
|
294
|
+
async def wrapper(*args, **kwargs):
|
|
295
|
+
_decorator_calls["get"] += 1
|
|
296
|
+
return await func(*args, **kwargs)
|
|
297
|
+
|
|
298
|
+
return wrapper
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def track_post_decorator(func):
|
|
302
|
+
"""Decorator that tracks POST endpoint calls."""
|
|
303
|
+
from functools import wraps
|
|
304
|
+
|
|
305
|
+
@wraps(func)
|
|
306
|
+
async def wrapper(*args, **kwargs):
|
|
307
|
+
_decorator_calls["post"] += 1
|
|
308
|
+
return await func(*args, **kwargs)
|
|
309
|
+
|
|
310
|
+
return wrapper
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class TestM2MWithDecoratorsViewSet(GenericAPIViewSet):
|
|
314
|
+
"""ViewSet using M2M relations with custom decorators."""
|
|
315
|
+
|
|
316
|
+
model = models.TestModelSerializerManyToMany
|
|
317
|
+
m2m_relations = [
|
|
318
|
+
M2MRelationSchema(
|
|
319
|
+
model=models.TestModelSerializerReverseManyToMany,
|
|
320
|
+
related_name="test_model_serializers",
|
|
321
|
+
filters={"name": (str, "")},
|
|
322
|
+
get_decorators=[track_get_decorator],
|
|
323
|
+
post_decorators=[track_post_decorator],
|
|
324
|
+
append_slash=True,
|
|
325
|
+
)
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
def test_model_serializers_query_params_handler(self, queryset, filters):
|
|
329
|
+
name_filter = filters.get("name")
|
|
330
|
+
if name_filter:
|
|
331
|
+
queryset = queryset.filter(name=name_filter)
|
|
332
|
+
return queryset
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
@tag("many_to_many_api", "decorators")
|
|
336
|
+
class M2MRelationSchemaDecoratorsTestCase(Tests.BaseManyToManyAPITestCase):
|
|
337
|
+
"""Test M2M API with custom decorators applied to GET and POST endpoints."""
|
|
338
|
+
|
|
339
|
+
viewset_class = TestM2MWithDecoratorsViewSet
|
|
340
|
+
related_model = models.TestModelSerializerReverseManyToMany
|
|
341
|
+
related_name = "test_model_serializers"
|
|
342
|
+
api_namespace = "m2m_decorators_test"
|
|
343
|
+
related_names = ["dec_a", "dec_b", "dec_c"]
|
|
344
|
+
|
|
345
|
+
def setUp(self):
|
|
346
|
+
super().setUp()
|
|
347
|
+
# Reset decorator call counts before each test
|
|
348
|
+
_decorator_calls["get"] = 0
|
|
349
|
+
_decorator_calls["post"] = 0
|
|
350
|
+
|
|
351
|
+
async def test_get_decorator_is_applied(self):
|
|
352
|
+
"""Test that get_decorators are applied to the GET endpoint."""
|
|
353
|
+
# First add some related objects
|
|
354
|
+
await self._add_related()
|
|
355
|
+
initial_get_count = _decorator_calls["get"]
|
|
356
|
+
|
|
357
|
+
# Call the GET endpoint
|
|
358
|
+
await self.get_view(request=self.request.get(), pk=self.path_schema)
|
|
359
|
+
|
|
360
|
+
# Verify the get decorator was called
|
|
361
|
+
self.assertEqual(
|
|
362
|
+
_decorator_calls["get"],
|
|
363
|
+
initial_get_count + 1,
|
|
364
|
+
"GET decorator should have been called once",
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
async def test_post_decorator_is_applied(self):
|
|
368
|
+
"""Test that post_decorators are applied to the POST endpoint."""
|
|
369
|
+
initial_post_count = _decorator_calls["post"]
|
|
370
|
+
|
|
371
|
+
# Call the POST endpoint to add related objects
|
|
372
|
+
await self._add_related()
|
|
373
|
+
|
|
374
|
+
# Verify the post decorator was called
|
|
375
|
+
self.assertEqual(
|
|
376
|
+
_decorator_calls["post"],
|
|
377
|
+
initial_post_count + 1,
|
|
378
|
+
"POST decorator should have been called once",
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
async def test_decorators_independent(self):
|
|
382
|
+
"""Test that GET and POST decorators are applied independently."""
|
|
383
|
+
# Reset counts
|
|
384
|
+
_decorator_calls["get"] = 0
|
|
385
|
+
_decorator_calls["post"] = 0
|
|
386
|
+
|
|
387
|
+
# Call POST endpoint
|
|
388
|
+
await self._add_related()
|
|
389
|
+
self.assertEqual(_decorator_calls["post"], 1)
|
|
390
|
+
self.assertEqual(_decorator_calls["get"], 0)
|
|
391
|
+
|
|
392
|
+
# Call GET endpoint
|
|
393
|
+
await self.get_view(request=self.request.get(), pk=self.path_schema)
|
|
394
|
+
self.assertEqual(_decorator_calls["post"], 1) # Still 1
|
|
395
|
+
self.assertEqual(_decorator_calls["get"], 1)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
@tag("many_to_many_api", "decorators", "schema")
|
|
399
|
+
class M2MRelationSchemaDecoratorsFieldTestCase(TestCase):
|
|
400
|
+
"""Test cases for M2MRelationSchema decorator fields."""
|
|
401
|
+
|
|
402
|
+
def test_decorators_default_to_empty_list(self):
|
|
403
|
+
"""Test that decorators default to empty lists."""
|
|
404
|
+
schema = M2MRelationSchema(
|
|
405
|
+
model=models.TestModelSerializerReverseManyToMany,
|
|
406
|
+
related_name="test_model_serializers",
|
|
407
|
+
)
|
|
408
|
+
self.assertEqual(schema.get_decorators, [])
|
|
409
|
+
self.assertEqual(schema.post_decorators, [])
|
|
410
|
+
|
|
411
|
+
def test_decorators_accept_list_of_callables(self):
|
|
412
|
+
"""Test that decorators accept a list of callables."""
|
|
413
|
+
|
|
414
|
+
def custom_decorator(func):
|
|
415
|
+
return func
|
|
416
|
+
|
|
417
|
+
schema = M2MRelationSchema(
|
|
418
|
+
model=models.TestModelSerializerReverseManyToMany,
|
|
419
|
+
related_name="test_model_serializers",
|
|
420
|
+
get_decorators=[custom_decorator],
|
|
421
|
+
post_decorators=[custom_decorator, custom_decorator],
|
|
422
|
+
)
|
|
423
|
+
self.assertEqual(len(schema.get_decorators), 1)
|
|
424
|
+
self.assertEqual(len(schema.post_decorators), 2)
|
|
425
|
+
self.assertEqual(schema.get_decorators[0], custom_decorator)
|
|
426
|
+
|
|
427
|
+
def test_decorators_can_be_none(self):
|
|
428
|
+
"""Test that decorators can explicitly be set to None."""
|
|
429
|
+
schema = M2MRelationSchema(
|
|
430
|
+
model=models.TestModelSerializerReverseManyToMany,
|
|
431
|
+
related_name="test_model_serializers",
|
|
432
|
+
get_decorators=None,
|
|
433
|
+
post_decorators=None,
|
|
434
|
+
)
|
|
435
|
+
# None values should be accepted
|
|
436
|
+
self.assertIsNone(schema.get_decorators)
|
|
437
|
+
self.assertIsNone(schema.post_decorators)
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/.github/workflows/coverage.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/models/model_serializer.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/models/serializers.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/renderers/orjson_renderer.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/api/views/api_view_set.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/installation.md
RENAMED
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/getting_started/quick_start.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/docs/tutorial/authentication.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/decorators/__init__.py
RENAMED
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/decorators/operations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/factory/operations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/ninja_aio/models/serializers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/test_exceptions_api.py
RENAMED
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/core/test_renderer_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/models/test_model_util.py
RENAMED
|
File without changes
|
{django_ninja_aio_crud-2.15.1 → django_ninja_aio_crud-2.16.0}/tests/models/test_models_extra.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|