• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

barseghyanartur / django-rest-framework-tricks / 3680627646

pending completion
3680627646

push

github

Artur Barseghyan
Up docs

170 of 190 relevant lines covered (89.47%)

4.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/rest_framework_tricks/serializers/nested_proxy.py
1
"""
2
Serializers.
3

4
The following code is used in the usage examples of the ``ModelSerializer``
5
and ``HyperlinkedModelSerializer`` classes.
6

7
    >>> from rest_framework import serializers
8
    >>>
9
    >>> from .models import Book
10
    >>>
11
    >>>
12
    >>> class PublishingInformationSerializer(serializers.ModelSerializer):
13
    >>>
14
    >>>     publication_date = serializers.DateField(required=False)
15
    >>>     isbn = serializers.CharField(required=False)
16
    >>>     pages = serializers.IntegerField(required=False)
17
    >>>
18
    >>>     class Meta:
19
    >>>
20
    >>>         model = Book
21
    >>>         fields = (
22
    >>>             'publication_date',
23
    >>>             'isbn',
24
    >>>             'pages',
25
    >>>         )
26
    >>>         nested_proxy_field = True
27
    >>>
28
    >>>
29
    >>> class StockInformationSerializer(serializers.ModelSerializer):
30
    >>>
31
    >>>     class Meta:
32
    >>>
33
    >>>         model = Book
34
    >>>         fields = (
35
    >>>             'stock_count',
36
    >>>             'price',
37
    >>>             'state',
38
    >>>         )
39
    >>>         nested_proxy_field = True
40
"""
41
from rest_framework import serializers
5✔
42

43

44
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
5✔
45
__copyright__ = "2017-2022 Artur Barseghyan"
5✔
46
__license__ = "GPL-2.0-only OR LGPL-2.1-or-later"
5✔
47
__all__ = (
5✔
48
    "extract_nested_serializers",
49
    "HyperlinkedModelSerializer",
50
    "is_nested_proxy_field",
51
    "ModelSerializer",
52
    "NestedProxyFieldIdentifier",
53
    "set_instance_values",
54
)
55

56

57
def is_nested_proxy_field(field):
5✔
58
    """Check if field is nested proxy field.
59

60
    :param field:
61
    :type field:
62
    :return: True or False
63
    :rtype: bool
64
    """
65
    return isinstance(field, NestedProxyFieldIdentifier) or (
5✔
66
        getattr(field, "Meta", False)
67
        and getattr(field.Meta, "nested_proxy_field", False)
68
    )
69

70

71
def extract_nested_serializers(
5✔
72
    serializer,
73
    validated_data,
74
    nested_serializers=None,
75
    nested_serializers_data=None,
76
):
77
    """Extract nested serializers.
78

79
    :param serializer: Serializer instance.
80
    :param validated_data: Validated data.
81
    :param nested_serializers:
82
    :param nested_serializers_data:
83
    :type serializer: rest_framework.serializers.Serializer
84
    :type validated_data: dict
85
    :type nested_serializers: dict
86
    :type nested_serializers_data:
87
    :return:
88
    :rtype: tuple
89
    """
90
    if nested_serializers is None:
5✔
91
        nested_serializers = {}
5✔
92
    if nested_serializers_data is None:
5✔
93
        nested_serializers_data = {}
5✔
94

95
    for __field_name, __field in serializer.fields.items():
5✔
96
        if is_nested_proxy_field(__field) and __field_name in validated_data:
5✔
97
            __serializer_data = validated_data.pop(__field_name)
5✔
98
            nested_serializers[__field_name] = __field
5✔
99
            nested_serializers_data[__field_name] = __serializer_data
5✔
100

101
    return nested_serializers, nested_serializers_data
5✔
102

103

104
def set_instance_values(nested_serializers, nested_serializers_data, instance):
5✔
105
    """Set values on instance.
106

107
    Does not perform any save actions.
108

109
    :param nested_serializers: Nested serializers.
110
    :param nested_serializers_data: Nested serializers data.
111
    :param instance: Instance (not yet saved)
112
    :type nested_serializers:
113
    :type nested_serializers_data:
114
    :type instance:
115
    :return: Same instance with values set.
116
    :rtype:
117
    """
118
    for __serializer_name, __serializer in nested_serializers_data.items():
5✔
119
        for __field_name, __field_value in __serializer.items():
5✔
120
            if is_nested_proxy_field(
5✔
121
                nested_serializers[__serializer_name][__field_name]
122
            ):
123
                set_instance_values(
5✔
124
                    {
125
                        __field_name: nested_serializers[__serializer_name][
126
                            __field_name
127
                        ]
128
                    },
129
                    {__field_name: __field_value},
130
                    instance,
131
                )
132
            else:
133
                setattr(instance, __field_name, __field_value)
5✔
134

135

136
class NestedProxyFieldIdentifier:
5✔
137
    """NestedProxyField identifier."""
138

139

140
class ModelSerializer(serializers.ModelSerializer):
5✔
141
    """ModelSerializer for models with NestedProxyField fields.
142

143
    Example:
144

145
    >>> from rest_framework_tricks.serializers import ModelSerializer
146
    >>>
147
    >>>
148
    >>> class BookSerializer(ModelSerializer):
149
    >>>
150
    >>>     publishing_information = PublishingInformationSerializer(
151
    >>>         required=False
152
    >>>     )
153
    >>>     stock_information = StockInformationSerializer(required=False)
154
    >>>
155
    >>>     class Meta:
156
    >>>
157
    >>>         model = Book
158
    >>>         fields = (
159
    >>>             'url',
160
    >>>             'id',
161
    >>>             'title',
162
    >>>             'description',
163
    >>>             'summary',
164
    >>>             'publishing_information',
165
    >>>             'stock_information',
166
    >>>         )
167
    """
168

169
    def create(self, validated_data):
5✔
170
        """Create.
171

172
        :param validated_data:
173
        :return:
174
        """
175
        # Collect information on nested serializers
176
        (
5✔
177
            __nested_serializers,
178
            __nested_serializers_data,
179
        ) = extract_nested_serializers(
180
            self,
181
            validated_data,
182
        )
183

184
        # Create instance, but don't save it yet
185
        instance = self.Meta.model(**validated_data)
5✔
186

187
        # Assign fields to the `instance` one by one
188
        set_instance_values(
5✔
189
            __nested_serializers, __nested_serializers_data, instance
190
        )
191

192
        # Save the instance and return
193
        instance.save()
5✔
194
        return instance
5✔
195

196
    def update(self, instance, validated_data):
5✔
197
        """Update.
198

199
        :param instance:
200
        :param validated_data:
201
        :return:
202
        """
203
        # Collect information on nested serializers
204
        (
5✔
205
            __nested_serializers,
206
            __nested_serializers_data,
207
        ) = extract_nested_serializers(
208
            self,
209
            validated_data,
210
        )
211

212
        # Update the instance
213
        instance = super(ModelSerializer, self).update(
5✔
214
            instance, validated_data
215
        )
216

217
        # Assign fields to the `instance` one by one
218
        set_instance_values(
5✔
219
            __nested_serializers, __nested_serializers_data, instance
220
        )
221

222
        # Save the instance and return
223
        instance.save()
5✔
224
        return instance
5✔
225

226

227
class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
5✔
228
    """HyperlinkedModelSerializer for models with NestedProxyField fields.
229

230
    Example:
231

232
    >>> from rest_framework_tricks.serializers import (
233
    >>>     HyperlinkedModelSerializer,
234
    >>> )
235
    >>>
236
    >>>
237
    >>> class BookSerializer(HyperlinkedModelSerializer):
238
    >>>
239
    >>>     publishing_information = PublishingInformationSerializer(
240
    >>>         required=False
241
    >>>     )
242
    >>>     stock_information = StockInformationSerializer(required=False)
243
    >>>
244
    >>>     class Meta:
245
    >>>
246
    >>>         model = Book
247
    >>>         fields = (
248
    >>>             'url',
249
    >>>             'id',
250
    >>>             'title',
251
    >>>             'description',
252
    >>>             'summary',
253
    >>>             'publishing_information',
254
    >>>             'stock_information',
255
    >>>         )
256
    """
257

258
    def create(self, validated_data):
5✔
259
        """Create.
260

261
        :param validated_data:
262
        :return:
263
        """
264
        # Collect information on nested serializers
265
        (
5✔
266
            __nested_serializers,
267
            __nested_serializers_data,
268
        ) = extract_nested_serializers(
269
            self,
270
            validated_data,
271
        )
272

273
        # Create instance, but don't save it yet
274
        instance = self.Meta.model(**validated_data)
5✔
275

276
        # Assign fields to the `instance` one by one
277
        set_instance_values(
5✔
278
            __nested_serializers, __nested_serializers_data, instance
279
        )
280

281
        # Save the instance and return
282
        instance.save()
5✔
283
        return instance
5✔
284

285
    def update(self, instance, validated_data):
5✔
286
        """Update.
287

288
        :param instance:
289
        :param validated_data:
290
        :return:
291
        """
292
        # Collect information on nested serializers
293
        (
5✔
294
            __nested_serializers,
295
            __nested_serializers_data,
296
        ) = extract_nested_serializers(
297
            self,
298
            validated_data,
299
        )
300

301
        # Update the instance
302
        instance = super(HyperlinkedModelSerializer, self).update(
5✔
303
            instance, validated_data
304
        )
305

306
        # Assign fields to the `instance` one by one
307
        set_instance_values(
5✔
308
            __nested_serializers, __nested_serializers_data, instance
309
        )
310

311
        # Save the instance and return
312
        instance.save()
5✔
313
        return instance
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc