Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework/utils/serializer_helpers.py: 50%
89 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from collections import OrderedDict
2from collections.abc import Mapping, MutableMapping
4from django.utils.encoding import force_str
6from rest_framework.utils import json
9class ReturnDict(OrderedDict):
10 """
11 Return object from `serializer.data` for the `Serializer` class.
12 Includes a backlink to the serializer instance for renderers
13 to use if they need richer field information.
14 """
16 def __init__(self, *args, **kwargs):
17 self.serializer = kwargs.pop('serializer')
18 super().__init__(*args, **kwargs)
20 def copy(self):
21 return ReturnDict(self, serializer=self.serializer)
23 def __repr__(self):
24 return dict.__repr__(self)
26 def __reduce__(self):
27 # Pickling these objects will drop the .serializer backlink,
28 # but preserve the raw data.
29 return (dict, (dict(self),))
32class ReturnList(list):
33 """
34 Return object from `serializer.data` for the `SerializerList` class.
35 Includes a backlink to the serializer instance for renderers
36 to use if they need richer field information.
37 """
39 def __init__(self, *args, **kwargs):
40 self.serializer = kwargs.pop('serializer')
41 super().__init__(*args, **kwargs)
43 def __repr__(self):
44 return list.__repr__(self)
46 def __reduce__(self):
47 # Pickling these objects will drop the .serializer backlink,
48 # but preserve the raw data.
49 return (list, (list(self),))
52class BoundField:
53 """
54 A field object that also includes `.value` and `.error` properties.
55 Returned when iterating over a serializer instance,
56 providing an API similar to Django forms and form fields.
57 """
59 def __init__(self, field, value, errors, prefix=''):
60 self._field = field
61 self._prefix = prefix
62 self.value = value
63 self.errors = errors
64 self.name = prefix + self.field_name
66 def __getattr__(self, attr_name):
67 return getattr(self._field, attr_name)
69 @property
70 def _proxy_class(self):
71 return self._field.__class__
73 def __repr__(self):
74 return '<%s value=%s errors=%s>' % (
75 self.__class__.__name__, self.value, self.errors
76 )
78 def as_form_field(self):
79 value = '' if (self.value is None or self.value is False) else self.value
80 return self.__class__(self._field, value, self.errors, self._prefix)
83class JSONBoundField(BoundField):
84 def as_form_field(self):
85 value = self.value
86 # When HTML form input is used and the input is not valid
87 # value will be a JSONString, rather than a JSON primitive.
88 if not getattr(value, 'is_json_string', False):
89 try:
90 value = json.dumps(
91 self.value,
92 sort_keys=True,
93 indent=4,
94 separators=(',', ': '),
95 )
96 except (TypeError, ValueError):
97 pass
98 return self.__class__(self._field, value, self.errors, self._prefix)
101class NestedBoundField(BoundField):
102 """
103 This `BoundField` additionally implements __iter__ and __getitem__
104 in order to support nested bound fields. This class is the type of
105 `BoundField` that is used for serializer fields.
106 """
108 def __init__(self, field, value, errors, prefix=''):
109 if value is None or value == '' or not isinstance(value, Mapping):
110 value = {}
111 super().__init__(field, value, errors, prefix)
113 def __iter__(self):
114 for field in self.fields.values():
115 yield self[field.field_name]
117 def __getitem__(self, key):
118 field = self.fields[key]
119 value = self.value.get(key) if self.value else None
120 error = self.errors.get(key) if isinstance(self.errors, dict) else None
121 if hasattr(field, 'fields'):
122 return NestedBoundField(field, value, error, prefix=self.name + '.')
123 elif getattr(field, '_is_jsonfield', False):
124 return JSONBoundField(field, value, error, prefix=self.name + '.')
125 return BoundField(field, value, error, prefix=self.name + '.')
127 def as_form_field(self):
128 values = {}
129 for key, value in self.value.items():
130 if isinstance(value, (list, dict)):
131 values[key] = value
132 else:
133 values[key] = '' if (value is None or value is False) else force_str(value)
134 return self.__class__(self._field, values, self.errors, self._prefix)
137class BindingDict(MutableMapping):
138 """
139 This dict-like object is used to store fields on a serializer.
141 This ensures that whenever fields are added to the serializer we call
142 `field.bind()` so that the `field_name` and `parent` attributes
143 can be set correctly.
144 """
146 def __init__(self, serializer):
147 self.serializer = serializer
148 self.fields = OrderedDict()
150 def __setitem__(self, key, field):
151 self.fields[key] = field
152 field.bind(field_name=key, parent=self.serializer)
154 def __getitem__(self, key):
155 return self.fields[key]
157 def __delitem__(self, key):
158 del self.fields[key]
160 def __iter__(self):
161 return iter(self.fields)
163 def __len__(self):
164 return len(self.fields)
166 def __repr__(self):
167 return dict.__repr__(self.fields)