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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy