Skip to content

Commit b9b50bd

Browse files
tienne-Bsaadullahaleem
authored andcommitted
Make set_value a method within Serializer (encode#8001)
* Make set_value a static method for Serializers As an alternative to encode#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 8d7e250 commit b9b50bd

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
@@ -765,6 +765,27 @@ class TestSerializer(serializers.Serializer):
765765
assert ({} | s.data).__class__ == s.data.__class__
766766

767767

768+
class TestSetValueMethod:
769+
# Serializer.set_value() modifies the first parameter in-place.
770+
771+
s = serializers.Serializer()
772+
773+
def test_no_keys(self):
774+
ret = {'a': 1}
775+
self.s.set_value(ret, [], {'b': 2})
776+
assert ret == {'a': 1, 'b': 2}
777+
778+
def test_one_key(self):
779+
ret = {'a': 1}
780+
self.s.set_value(ret, ['x'], 2)
781+
assert ret == {'a': 1, 'x': 2}
782+
783+
def test_nested_key(self):
784+
ret = {'a': 1}
785+
self.s.set_value(ret, ['x', 'y'], 2)
786+
assert ret == {'a': 1, 'x': {'y': 2}}
787+
788+
768789
class MyClass(models.Model):
769790
name = models.CharField(max_length=100)
770791
value = models.CharField(max_length=100, blank=True)

0 commit comments

Comments
 (0)