Skip to content

Commit d252d22

Browse files
authored
Make set_value a method within Serializer (#8001)
* Make set_value a static method for Serializers As an alternative to #7671, let the method be overridden if needed. As the function is only used for serializers, it has a better place in the Serializer class. * Set `set_value` as an object (non-static) method * Add tests for set_value() These tests follow the examples given in the method.
1 parent a25aac7 commit d252d22

File tree

3 files changed

+43
-23
lines changed

3 files changed

+43
-23
lines changed

rest_framework/fields.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,6 @@ def get_attribute(instance, attrs):
113113
return instance
114114

115115

116-
def set_value(dictionary, keys, value):
117-
"""
118-
Similar to Python's built in `dictionary[key] = value`,
119-
but takes a list of nested keys instead of a single key.
120-
121-
set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2}
122-
set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2}
123-
set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}}
124-
"""
125-
if not keys:
126-
dictionary.update(value)
127-
return
128-
129-
for key in keys[:-1]:
130-
if key not in dictionary:
131-
dictionary[key] = {}
132-
dictionary = dictionary[key]
133-
134-
dictionary[keys[-1]] = value
135-
136-
137116
def to_choices_dict(choices):
138117
"""
139118
Convert choices into key/value dicts.

rest_framework/serializers.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
from rest_framework.compat import postgres_fields
3030
from rest_framework.exceptions import ErrorDetail, ValidationError
31-
from rest_framework.fields import get_error_detail, set_value
31+
from rest_framework.fields import get_error_detail
3232
from rest_framework.settings import api_settings
3333
from rest_framework.utils import html, model_meta, representation
3434
from rest_framework.utils.field_mapping import (
@@ -346,6 +346,26 @@ class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
346346
'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
347347
}
348348

349+
def set_value(self, dictionary, keys, value):
350+
"""
351+
Similar to Python's built in `dictionary[key] = value`,
352+
but takes a list of nested keys instead of a single key.
353+
354+
set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2}
355+
set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2}
356+
set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}}
357+
"""
358+
if not keys:
359+
dictionary.update(value)
360+
return
361+
362+
for key in keys[:-1]:
363+
if key not in dictionary:
364+
dictionary[key] = {}
365+
dictionary = dictionary[key]
366+
367+
dictionary[keys[-1]] = value
368+
349369
@cached_property
350370
def fields(self):
351371
"""
@@ -492,7 +512,7 @@ def to_internal_value(self, data):
492512
except SkipField:
493513
pass
494514
else:
495-
set_value(ret, field.source_attrs, validated_value)
515+
self.set_value(ret, field.source_attrs, validated_value)
496516

497517
if errors:
498518
raise ValidationError(errors)

tests/test_serializer.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,3 +762,24 @@ class TestSerializer(serializers.Serializer):
762762

763763
assert (s.data | {}).__class__ == s.data.__class__
764764
assert ({} | s.data).__class__ == s.data.__class__
765+
766+
767+
class TestSetValueMethod:
768+
# Serializer.set_value() modifies the first parameter in-place.
769+
770+
s = serializers.Serializer()
771+
772+
def test_no_keys(self):
773+
ret = {'a': 1}
774+
self.s.set_value(ret, [], {'b': 2})
775+
assert ret == {'a': 1, 'b': 2}
776+
777+
def test_one_key(self):
778+
ret = {'a': 1}
779+
self.s.set_value(ret, ['x'], 2)
780+
assert ret == {'a': 1, 'x': 2}
781+
782+
def test_nested_key(self):
783+
ret = {'a': 1}
784+
self.s.set_value(ret, ['x', 'y'], 2)
785+
assert ret == {'a': 1, 'x': {'y': 2}}

0 commit comments

Comments
 (0)