55from django .core .exceptions import ValidationError
66from django .db import models
77from django .db .models import NOT_PROVIDED
8+ from rest_framework import serializers
89from rest_framework .fields import empty
910from rest_framework .relations import ManyRelatedField
1011
1112from django_features .custom_fields .serializers import CustomFieldBaseModelSerializer
1213from django_features .fields import UUIDRelatedField
1314
1415
15- class BaseMappingSerializer ( CustomFieldBaseModelSerializer ):
16+ class PropertySerializer ( serializers . Serializer ):
1617 relation_separator : str = "."
18+
19+ class Meta :
20+ abstract = True
21+ fields = "__all__"
22+ model = None
23+
24+ @property
25+ def mapping (self ) -> dict [str , dict [str , Any ]]:
26+ if getattr (self , "_mapping" ) is None :
27+ raise ValueError (
28+ "Property 'mapping' on instance must be set and can't be 'None'"
29+ )
30+ return self ._mapping
31+
32+ @mapping .setter
33+ def mapping (self , value : dict [str , dict [str , Any ]]) -> None :
34+ self ._mapping = value
35+
36+ @property
37+ def mapping_fields (self ) -> list [str ]:
38+ mapping_fields = getattr (
39+ self , "_mapping_fields" , list (self .model_mapping .values ())
40+ )
41+ if mapping_fields is None :
42+ raise ValueError ("Property 'mapping_fields' must be set and can't be 'None" )
43+ return mapping_fields
44+
45+ @mapping_fields .setter
46+ def mapping_fields (self , value : list [str ]) -> None :
47+ self ._mapping_fields = value
48+
49+ @property
50+ def model_mapping (self ) -> dict [str , Any ]:
51+ for key_path in self .mapping .keys ():
52+ key = key_path .split (self .relation_separator )[- 1 ]
53+ if key .lower () == self .model .__name__ .lower ():
54+ return self .mapping .get (key_path , {})
55+ return {}
56+
57+ @model_mapping .setter
58+ def model_mapping (self , value : dict [str , Any ]) -> None :
59+ self ._model_mapping = value
60+
61+ @property
62+ def model (self ) -> models .Model :
63+ model = getattr (self , "_model" , self .Meta .model )
64+ if model is None :
65+ raise ValueError (
66+ "Property 'model' must be set and can't be 'None. Default is 'Meta.model"
67+ )
68+ return model
69+
70+ @model .setter
71+ def model (self , value : models .Model ) -> None :
72+ self ._model = value
73+
74+
75+ class BaseMappingSerializer (CustomFieldBaseModelSerializer , PropertySerializer ):
1776 serializer_related_field = UUIDRelatedField
1877 serializer_related_fields : dict [str , Any ] = {}
1978
@@ -32,26 +91,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
3291 self .exclude : list [str ] = []
3392 self .related_fields : set [str ] = set ()
3493
35- @property
36- def mapping (self ) -> dict [str , dict [str , Any ]]:
37- raise NotImplementedError ("Mapping must be set" )
38-
39- @property
40- def mapping_fields (self ) -> list [str ]:
41- raise NotImplementedError ("Mapping fields must be set" )
42-
43- @property
44- def model (self ) -> models .Model :
45- if self .Meta .model is None :
46- raise ValueError ("Meta.model must be set" )
47- return self .Meta .model
48-
4994 def get_fields (self ) -> dict [str , Any ]:
5095 initial_fields = super ().get_fields ()
5196 fields : dict [str , Any ] = dict ()
5297 nested_fields : dict [str , Any ] = dict ()
5398 nested_field_fields : dict [str , list [str ]] = dict ()
54- self .related_fields : set [str ] = set ()
5599 for internal_name in self .mapping_fields :
56100 if internal_name in self .exclude :
57101 continue
@@ -160,40 +204,16 @@ def __init__(
160204 ** kwargs : Any ,
161205 ) -> None :
162206 self .exclude = exclude
163- self .nested_fields = nested_fields
164- self .parent_mapping = parent_mapping
207+ self .mapping_fields = nested_fields
208+ self .mapping = parent_mapping
165209 self .Meta .model = field .related_model
166210 super ().__init__ (* args , ** kwargs )
167211
168- @property
169- def mapping (self ) -> dict [str , dict [str , Any ]]:
170- return self .parent_mapping
171212
172- @property
173- def mapping_fields (self ) -> list [str ]:
174- return self .nested_fields
175-
176-
177- class MappingSerializer (BaseMappingSerializer ):
213+ class DataMappingSerializer (PropertySerializer ):
178214 _default_prefix = "default"
179215 _format_prefix = "format"
180216
181- class Meta :
182- abstract = True
183- fields = "__all__"
184- model = None
185-
186- def __init__ (
187- self ,
188- instance : Any = None ,
189- data : Any = empty ,
190- ** kwargs : Any ,
191- ) -> None :
192- self .instance = instance
193- self .unmapped_data = data
194- mapped_data = self .map_data (data )
195- super ().__init__ (instance , data = mapped_data , ** kwargs )
196-
197217 def _get_nested_data (self , field_path : list [str ], data : Any ) -> tuple [Any , bool ]:
198218 field_name = field_path [0 ]
199219 if not isinstance (data , dict ):
@@ -248,17 +268,69 @@ def map_data(self, initial_data: Any) -> Any:
248268 )
249269 return data
250270
251- @property
252- def mapping_fields (self ) -> list [str ]:
253- return list (self .model_mapping .values ())
254271
255- @property
256- def model_mapping (self ) -> dict [str , Any ]:
257- mapping = getattr (self , "mapping" , None )
258- if mapping is None :
259- raise ValueError ("Mapping must be set" )
260- for key_path in mapping .keys ():
261- key = key_path .split (self .relation_separator )[- 1 ]
262- if key .lower () == self .model .__name__ .lower ():
263- return mapping .get (key_path , {})
264- return {}
272+ class ListDataMappingSerializer (serializers .ListSerializer , DataMappingSerializer ):
273+ def __init__ (self , data : Any = empty , * args : Any , ** kwargs : Any ) -> None :
274+ self .instance = None
275+ self .mapping = kwargs .pop ("mapping" , {})
276+ self .model = kwargs .pop ("model" )
277+ self .unmapped_data = data if data is not empty else []
278+ mapped_data = self .map_list_data (self .unmapped_data )
279+ super ().__init__ (data = mapped_data , * args , ** kwargs )
280+
281+ def map_list_data (self , initial_data : Any ) -> list [Any ]:
282+ list_data : list [dict [str , Any ]] = []
283+ for item in initial_data :
284+ list_data .append (self .map_data (item ))
285+ return list_data
286+
287+
288+ class MappingSerializer (BaseMappingSerializer , DataMappingSerializer ):
289+ list_serializer_class = ListDataMappingSerializer
290+
291+ class Meta :
292+ abstract = True
293+ fields = "__all__"
294+ model = None
295+
296+ def __init__ (
297+ self ,
298+ instance : Any = None ,
299+ data : Any = empty ,
300+ ** kwargs : Any ,
301+ ) -> None :
302+ self .instance = instance
303+ self .unmapped_data = data
304+ mapped_data = self .map_data (data )
305+ super ().__init__ (instance , data = mapped_data , ** kwargs )
306+
307+ @classmethod
308+ def many_init (cls , * args : Any , ** kwargs : Any ) -> ListDataMappingSerializer :
309+ """
310+ Overwrite the many_init function from the ModelSerializer to change the default listing serializer to the given
311+ list_serializer_class attribute instead of the default ListSerializer. Therefore, the list serializer class can
312+ be set with the attribute list_serializer_class on the serializer class instead of the Meta class.
313+ """
314+
315+ list_kwargs = {}
316+ for key in serializers .LIST_SERIALIZER_KWARGS_REMOVE :
317+ value = kwargs .pop (key , None )
318+ if value is not None :
319+ list_kwargs [key ] = value
320+ child = cls (* args , ** kwargs )
321+ list_kwargs ["child" ] = child
322+ list_kwargs ["mapping" ] = getattr (child , "mapping" , {})
323+ list_kwargs .update (
324+ {
325+ key : value
326+ for key , value in kwargs .items ()
327+ if key in serializers .LIST_SERIALIZER_KWARGS
328+ }
329+ )
330+ meta = getattr (cls , "Meta" , None )
331+ list_serializer_class = getattr (
332+ meta , "list_serializer_class" , cls .list_serializer_class
333+ )
334+ model = getattr (meta , "model" , None )
335+ list_kwargs ["model" ] = model
336+ return list_serializer_class (* args , ** list_kwargs )
0 commit comments