django-ninja-aio-crud 2.6.1__py3-none-any.whl → 2.7.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.6.1.dist-info → django_ninja_aio_crud-2.7.0.dist-info}/METADATA +1 -1
- {django_ninja_aio_crud-2.6.1.dist-info → django_ninja_aio_crud-2.7.0.dist-info}/RECORD +6 -6
- ninja_aio/__init__.py +1 -1
- ninja_aio/models/serializers.py +146 -27
- {django_ninja_aio_crud-2.6.1.dist-info → django_ninja_aio_crud-2.7.0.dist-info}/WHEEL +0 -0
- {django_ninja_aio_crud-2.6.1.dist-info → django_ninja_aio_crud-2.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ninja_aio/__init__.py,sha256=
|
|
1
|
+
ninja_aio/__init__.py,sha256=FkPurmyPz8Yv7VAiIOZYbFEghPXZ7aeLYX5xBwFSMtk,119
|
|
2
2
|
ninja_aio/api.py,sha256=tuC7vdvn7s1GkCnSFy9Kn1zv0glZfYptRQVvo8ZRtGQ,2429
|
|
3
3
|
ninja_aio/auth.py,sha256=4sWdFPjKiQgUL1d_CSGDblVjnY5ptP6LQha6XXdluJA,9157
|
|
4
4
|
ninja_aio/exceptions.py,sha256=_3xFqfFCOfrrMhSA0xbMqgXy8R0UQjhXaExrFvaDAjY,3891
|
|
@@ -14,7 +14,7 @@ ninja_aio/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
14
14
|
ninja_aio/helpers/api.py,sha256=YMzuZ4-ZpUrJBQIabE26gb_GYwsH2rVosWRE95YfdPQ,20775
|
|
15
15
|
ninja_aio/helpers/query.py,sha256=lzaH-htswoJVRT-W736HGMkpMba1VmN98TBLv5cZx9Q,4549
|
|
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=AlZIkwIiOt-nGBfMDoXu9tJotfzH5L13fv3Rw_4sKUg,35697
|
|
18
18
|
ninja_aio/models/utils.py,sha256=P-YfbVyzUfxm_s1BrgSd6Zs0HIGdZ79PU1qM0Ud9-Xs,30492
|
|
19
19
|
ninja_aio/schemas/__init__.py,sha256=iLBwHg0pmL9k_UkIui5Q8QIl_gO4fgxSv2JHxDzqnSI,549
|
|
20
20
|
ninja_aio/schemas/api.py,sha256=-VwXhBRhmMsZLIAmWJ-P7tB5klxXS75eukjabeKKYsc,360
|
|
@@ -23,7 +23,7 @@ ninja_aio/schemas/helpers.py,sha256=W6IeHi5Tmbjh3FXwDYqjqlLBTVj5uTYq3_JVkNUWayo,
|
|
|
23
23
|
ninja_aio/views/__init__.py,sha256=DEzjWA6y3WF0V10nNF8eEurLNEodgxKzyFd09AqVp3s,148
|
|
24
24
|
ninja_aio/views/api.py,sha256=GRtjCvAv7jAp3TxpOirsbMVKpBd8hymSMILdE-JLxvI,21327
|
|
25
25
|
ninja_aio/views/mixins.py,sha256=Jh6BG8Cs823nurVlODlzCquTxKrLH7Pmo5udPqUGZek,11378
|
|
26
|
-
django_ninja_aio_crud-2.
|
|
27
|
-
django_ninja_aio_crud-2.
|
|
28
|
-
django_ninja_aio_crud-2.
|
|
29
|
-
django_ninja_aio_crud-2.
|
|
26
|
+
django_ninja_aio_crud-2.7.0.dist-info/licenses/LICENSE,sha256=yrDAYcm0gRp_Qyzo3GQa4BjYjWRkAhGC8QRva__RYq0,1073
|
|
27
|
+
django_ninja_aio_crud-2.7.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
28
|
+
django_ninja_aio_crud-2.7.0.dist-info/METADATA,sha256=_eQi4SR0xvfnLM6ShB-yvkxffFzUsxNCB39spSHWTOU,9963
|
|
29
|
+
django_ninja_aio_crud-2.7.0.dist-info/RECORD,,
|
ninja_aio/__init__.py
CHANGED
ninja_aio/models/serializers.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, List, Optional
|
|
1
|
+
from typing import Any, List, Optional, Union, get_args, get_origin, ForwardRef
|
|
2
2
|
import warnings
|
|
3
3
|
import sys
|
|
4
4
|
|
|
@@ -69,19 +69,14 @@ class BaseSerializer:
|
|
|
69
69
|
raise NotImplementedError
|
|
70
70
|
|
|
71
71
|
@classmethod
|
|
72
|
-
def
|
|
72
|
+
def _resolve_string_reference(cls, string_ref: str) -> type:
|
|
73
73
|
"""
|
|
74
|
-
Resolve a serializer reference
|
|
75
|
-
|
|
76
|
-
This method performs lazy resolution, meaning it will attempt to resolve
|
|
77
|
-
string references only when called, allowing for forward references and
|
|
78
|
-
circular dependencies between serializers in the same module.
|
|
74
|
+
Resolve a string serializer reference to an actual class.
|
|
79
75
|
|
|
80
76
|
Parameters
|
|
81
77
|
----------
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
or an actual serializer class.
|
|
78
|
+
string_ref : str
|
|
79
|
+
String reference (local class name or absolute import path).
|
|
85
80
|
|
|
86
81
|
Returns
|
|
87
82
|
-------
|
|
@@ -93,35 +88,152 @@ class BaseSerializer:
|
|
|
93
88
|
ValueError
|
|
94
89
|
If the string reference cannot be resolved.
|
|
95
90
|
"""
|
|
96
|
-
#
|
|
97
|
-
if
|
|
98
|
-
|
|
91
|
+
# Check if it's an absolute import path (contains dots)
|
|
92
|
+
if "." in string_ref:
|
|
93
|
+
# Absolute import path: "myapp.serializers.UserSerializer"
|
|
94
|
+
module_path, class_name = string_ref.rsplit(".", 1)
|
|
99
95
|
|
|
100
|
-
|
|
96
|
+
try:
|
|
97
|
+
# Try to get or import the module
|
|
98
|
+
module = sys.modules.get(module_path)
|
|
99
|
+
if module is None:
|
|
100
|
+
import importlib
|
|
101
|
+
module = importlib.import_module(module_path)
|
|
102
|
+
|
|
103
|
+
# Get the serializer class from the module
|
|
104
|
+
serializer_class = getattr(module, class_name, None)
|
|
105
|
+
|
|
106
|
+
if serializer_class is None:
|
|
107
|
+
raise ValueError(
|
|
108
|
+
f"Cannot resolve serializer reference '{string_ref}': "
|
|
109
|
+
f"class '{class_name}' not found in module '{module_path}'."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return serializer_class
|
|
113
|
+
except ImportError as e:
|
|
114
|
+
raise ValueError(
|
|
115
|
+
f"Cannot resolve serializer reference '{string_ref}': "
|
|
116
|
+
f"failed to import module '{module_path}': {e}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Local reference: simple class name in the same module
|
|
101
120
|
module = sys.modules.get(cls.__module__)
|
|
102
121
|
|
|
103
122
|
if module is None:
|
|
104
123
|
raise ValueError(
|
|
105
|
-
f"Cannot resolve serializer reference '{
|
|
124
|
+
f"Cannot resolve serializer reference '{string_ref}': "
|
|
106
125
|
f"module '{cls.__module__}' not found in sys.modules."
|
|
107
126
|
)
|
|
108
127
|
|
|
109
|
-
|
|
110
|
-
serializer_class = getattr(module, serializer_ref, None)
|
|
128
|
+
serializer_class = getattr(module, string_ref, None)
|
|
111
129
|
|
|
112
130
|
if serializer_class is None:
|
|
113
131
|
raise ValueError(
|
|
114
|
-
f"Cannot resolve serializer reference '{
|
|
115
|
-
f"Make sure the serializer class '{
|
|
132
|
+
f"Cannot resolve serializer reference '{string_ref}' in module '{cls.__module__}'. "
|
|
133
|
+
f"Make sure the serializer class '{string_ref}' is defined in the same module as {cls.__name__}."
|
|
116
134
|
)
|
|
117
135
|
|
|
118
136
|
return serializer_class
|
|
119
137
|
|
|
138
|
+
@classmethod
|
|
139
|
+
def _resolve_serializer_reference(cls, serializer_ref: str | type | Any) -> type | Any:
|
|
140
|
+
"""
|
|
141
|
+
Resolve a serializer reference that may be a string, a class, or a Union of serializers.
|
|
142
|
+
|
|
143
|
+
This method performs lazy resolution, meaning it will attempt to resolve
|
|
144
|
+
string references only when called, allowing for forward references and
|
|
145
|
+
circular dependencies between serializers in the same module.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
serializer_ref : str | type | Union
|
|
150
|
+
Either a string reference to a serializer class, an actual serializer class,
|
|
151
|
+
or a Union of serializer references. String references can be:
|
|
152
|
+
- A class name in the same module (e.g., "UserSerializer")
|
|
153
|
+
- An absolute import path (e.g., "myapp.serializers.UserSerializer")
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
type | Union
|
|
158
|
+
The resolved serializer class or Union of serializer classes.
|
|
159
|
+
|
|
160
|
+
Raises
|
|
161
|
+
------
|
|
162
|
+
ValueError
|
|
163
|
+
If the string reference cannot be resolved.
|
|
164
|
+
|
|
165
|
+
Examples
|
|
166
|
+
--------
|
|
167
|
+
>>> # Single reference
|
|
168
|
+
>>> cls._resolve_serializer_reference("UserSerializer")
|
|
169
|
+
>>> cls._resolve_serializer_reference(UserSerializer)
|
|
170
|
+
>>>
|
|
171
|
+
>>> # Union reference
|
|
172
|
+
>>> from typing import Union
|
|
173
|
+
>>> cls._resolve_serializer_reference(Union[UserSerializer, AdminSerializer])
|
|
174
|
+
>>> cls._resolve_serializer_reference(Union["UserSerializer", "AdminSerializer"])
|
|
175
|
+
"""
|
|
176
|
+
# Handle Union types
|
|
177
|
+
origin = get_origin(serializer_ref)
|
|
178
|
+
if origin is Union:
|
|
179
|
+
resolved_types = tuple(
|
|
180
|
+
cls._resolve_serializer_reference(arg)
|
|
181
|
+
for arg in get_args(serializer_ref)
|
|
182
|
+
)
|
|
183
|
+
# Optimize single-type unions
|
|
184
|
+
if len(resolved_types) == 1:
|
|
185
|
+
return resolved_types[0]
|
|
186
|
+
# Create Union using indexing syntax for Python 3.10+ compatibility
|
|
187
|
+
return Union[resolved_types]
|
|
188
|
+
|
|
189
|
+
# Handle ForwardRef (created when using Union["StringType"])
|
|
190
|
+
if isinstance(serializer_ref, ForwardRef):
|
|
191
|
+
return cls._resolve_serializer_reference(serializer_ref.__forward_arg__)
|
|
192
|
+
|
|
193
|
+
# Handle string references
|
|
194
|
+
if isinstance(serializer_ref, str):
|
|
195
|
+
return cls._resolve_string_reference(serializer_ref)
|
|
196
|
+
|
|
197
|
+
# Already a class, return as-is
|
|
198
|
+
return serializer_ref
|
|
199
|
+
|
|
120
200
|
@classmethod
|
|
121
201
|
def _get_relations_serializers(cls) -> dict[str, "Serializer"]:
|
|
122
202
|
# Optional in subclasses. Default to no explicit relation serializers.
|
|
123
203
|
return {}
|
|
124
204
|
|
|
205
|
+
@classmethod
|
|
206
|
+
def _generate_union_schema(cls, resolved_union: Any) -> Any:
|
|
207
|
+
"""
|
|
208
|
+
Generate a Union schema from multiple resolved serializers.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
resolved_union : Union
|
|
213
|
+
A Union type containing resolved serializer classes.
|
|
214
|
+
|
|
215
|
+
Returns
|
|
216
|
+
-------
|
|
217
|
+
Schema | Union[Schema, ...] | None
|
|
218
|
+
Union of generated schemas or None if all schemas are None.
|
|
219
|
+
"""
|
|
220
|
+
# Generate schemas for each serializer in the Union
|
|
221
|
+
schemas = tuple(
|
|
222
|
+
serializer_type.generate_related_s()
|
|
223
|
+
for serializer_type in get_args(resolved_union)
|
|
224
|
+
if serializer_type.generate_related_s() is not None
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if not schemas:
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
# Optimize single-schema unions
|
|
231
|
+
if len(schemas) == 1:
|
|
232
|
+
return schemas[0]
|
|
233
|
+
|
|
234
|
+
# Create Union of schemas using indexing syntax for Python 3.10+ compatibility
|
|
235
|
+
return Union[schemas]
|
|
236
|
+
|
|
125
237
|
@classmethod
|
|
126
238
|
def _resolve_relation_schema(cls, field_name: str, rel_model: models.Model):
|
|
127
239
|
"""
|
|
@@ -136,23 +248,30 @@ class BaseSerializer:
|
|
|
136
248
|
|
|
137
249
|
Returns
|
|
138
250
|
-------
|
|
139
|
-
Schema | None
|
|
140
|
-
Generated schema or None if cannot be resolved.
|
|
251
|
+
Schema | Union[Schema, ...] | None
|
|
252
|
+
Generated schema, Union of schemas, or None if cannot be resolved.
|
|
141
253
|
"""
|
|
142
|
-
#
|
|
254
|
+
# Auto-resolve ModelSerializer with readable fields
|
|
143
255
|
if isinstance(rel_model, ModelSerializerMeta):
|
|
144
256
|
if rel_model.get_fields("read") or rel_model.get_custom_fields("read"):
|
|
145
257
|
return rel_model.generate_related_s()
|
|
146
258
|
return None
|
|
147
259
|
|
|
148
|
-
#
|
|
260
|
+
# Resolve from explicit serializer mapping
|
|
149
261
|
rel_serializers = cls._get_relations_serializers() or {}
|
|
150
262
|
serializer_ref = rel_serializers.get(field_name)
|
|
151
|
-
if serializer_ref:
|
|
152
|
-
serializer = cls._resolve_serializer_reference(serializer_ref)
|
|
153
|
-
return serializer.generate_related_s()
|
|
154
263
|
|
|
155
|
-
|
|
264
|
+
if not serializer_ref:
|
|
265
|
+
return None
|
|
266
|
+
|
|
267
|
+
resolved = cls._resolve_serializer_reference(serializer_ref)
|
|
268
|
+
|
|
269
|
+
# Handle Union of serializers
|
|
270
|
+
if get_origin(resolved) is Union:
|
|
271
|
+
return cls._generate_union_schema(resolved)
|
|
272
|
+
|
|
273
|
+
# Handle single serializer
|
|
274
|
+
return resolved.generate_related_s()
|
|
156
275
|
|
|
157
276
|
@classmethod
|
|
158
277
|
def _is_special_field(
|
|
File without changes
|
{django_ninja_aio_crud-2.6.1.dist-info → django_ninja_aio_crud-2.7.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|