mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 09:36:49 +03:00
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.
This commit is contained in:
parent
a25aac7d67
commit
d252d22343
|
@ -113,27 +113,6 @@ def get_attribute(instance, attrs):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
def set_value(dictionary, keys, value):
|
|
||||||
"""
|
|
||||||
Similar to Python's built in `dictionary[key] = value`,
|
|
||||||
but takes a list of nested keys instead of a single key.
|
|
||||||
|
|
||||||
set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2}
|
|
||||||
set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2}
|
|
||||||
set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}}
|
|
||||||
"""
|
|
||||||
if not keys:
|
|
||||||
dictionary.update(value)
|
|
||||||
return
|
|
||||||
|
|
||||||
for key in keys[:-1]:
|
|
||||||
if key not in dictionary:
|
|
||||||
dictionary[key] = {}
|
|
||||||
dictionary = dictionary[key]
|
|
||||||
|
|
||||||
dictionary[keys[-1]] = value
|
|
||||||
|
|
||||||
|
|
||||||
def to_choices_dict(choices):
|
def to_choices_dict(choices):
|
||||||
"""
|
"""
|
||||||
Convert choices into key/value dicts.
|
Convert choices into key/value dicts.
|
||||||
|
|
|
@ -28,7 +28,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.compat import postgres_fields
|
from rest_framework.compat import postgres_fields
|
||||||
from rest_framework.exceptions import ErrorDetail, ValidationError
|
from rest_framework.exceptions import ErrorDetail, ValidationError
|
||||||
from rest_framework.fields import get_error_detail, set_value
|
from rest_framework.fields import get_error_detail
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.utils import html, model_meta, representation
|
from rest_framework.utils import html, model_meta, representation
|
||||||
from rest_framework.utils.field_mapping import (
|
from rest_framework.utils.field_mapping import (
|
||||||
|
@ -346,6 +346,26 @@ class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
|
||||||
'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
|
'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def set_value(self, dictionary, keys, value):
|
||||||
|
"""
|
||||||
|
Similar to Python's built in `dictionary[key] = value`,
|
||||||
|
but takes a list of nested keys instead of a single key.
|
||||||
|
|
||||||
|
set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2}
|
||||||
|
set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2}
|
||||||
|
set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}}
|
||||||
|
"""
|
||||||
|
if not keys:
|
||||||
|
dictionary.update(value)
|
||||||
|
return
|
||||||
|
|
||||||
|
for key in keys[:-1]:
|
||||||
|
if key not in dictionary:
|
||||||
|
dictionary[key] = {}
|
||||||
|
dictionary = dictionary[key]
|
||||||
|
|
||||||
|
dictionary[keys[-1]] = value
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def fields(self):
|
def fields(self):
|
||||||
"""
|
"""
|
||||||
|
@ -492,7 +512,7 @@ class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
|
||||||
except SkipField:
|
except SkipField:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
set_value(ret, field.source_attrs, validated_value)
|
self.set_value(ret, field.source_attrs, validated_value)
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
|
@ -762,3 +762,24 @@ class Test8301Regression:
|
||||||
|
|
||||||
assert (s.data | {}).__class__ == s.data.__class__
|
assert (s.data | {}).__class__ == s.data.__class__
|
||||||
assert ({} | s.data).__class__ == s.data.__class__
|
assert ({} | s.data).__class__ == s.data.__class__
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetValueMethod:
|
||||||
|
# Serializer.set_value() modifies the first parameter in-place.
|
||||||
|
|
||||||
|
s = serializers.Serializer()
|
||||||
|
|
||||||
|
def test_no_keys(self):
|
||||||
|
ret = {'a': 1}
|
||||||
|
self.s.set_value(ret, [], {'b': 2})
|
||||||
|
assert ret == {'a': 1, 'b': 2}
|
||||||
|
|
||||||
|
def test_one_key(self):
|
||||||
|
ret = {'a': 1}
|
||||||
|
self.s.set_value(ret, ['x'], 2)
|
||||||
|
assert ret == {'a': 1, 'x': 2}
|
||||||
|
|
||||||
|
def test_nested_key(self):
|
||||||
|
ret = {'a': 1}
|
||||||
|
self.s.set_value(ret, ['x', 'y'], 2)
|
||||||
|
assert ret == {'a': 1, 'x': {'y': 2}}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user