diff --git a/rest_framework/fields.py b/rest_framework/fields.py index fdfba13f26..de911df7eb 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -125,9 +125,14 @@ def set_value(dictionary, keys, value): for key in keys[:-1]: if key not in dictionary: dictionary[key] = {} + elif type(dictionary[key]) is not dict: + dictionary[key] = {'': dictionary[key]} dictionary = dictionary[key] - dictionary[keys[-1]] = value + if keys[-1] in dictionary and type(dictionary[keys[-1]]) is dict: + dictionary[keys[-1]][''] = value + else: + dictionary[keys[-1]] = value def to_choices_dict(choices): diff --git a/tests/test_fields.py b/tests/test_fields.py index fdd570d8a6..cdedf76142 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -14,7 +14,7 @@ import rest_framework from rest_framework import exceptions, serializers from rest_framework.fields import ( - BuiltinSignatureError, DjangoImageField, is_simple_callable + BuiltinSignatureError, DjangoImageField, is_simple_callable, set_value ) # Tests for helper functions. @@ -2380,3 +2380,65 @@ def validate(self, obj): ), ] } + + +# Tests for set_value function +# ---------------------------- + +class TestSetValue: + + def test_no_keys(self): + """ + If no keys are provided, but a dict as value, add the dicts + """ + d = {'a': 1} + set_value(d, [], {'b': 2}) + assert d == {'a': 1, 'b': 2} + + def test_one_key(self): + """ + If a key + value provided, add the value to the dict with key + """ + d = {'a': 1} + set_value(d, ['x'], 2) + assert d == {'a': 1, 'x': 2} + + def test_many_keys(self): + """ + With many keys, add the item to the in-most dict + """ + d = {'a': 1} + set_value(d, ['x', 'y'], 2) + assert d == {'a': 1, 'x': {'y': 2}} + + def test_many_keys_existing(self): + """ + With many keys with existing in-built dict + """ + d = {'a': 1, 'x': {'a': 2}} + set_value(d, ['x', 'y'], 3) + assert d == {'a': 1, 'x': {'a': 2, 'y': 3}} + + def test_conflicting_keys(self): + """ + If a value exists where a key will be added, use a blank key for old value + """ + d = {'a': 1, 'x': 2} + set_value(d, ['x', 'y'], 3) + assert d == {'a': 1, 'x': {'': 2, 'y': 3}} + + def test_reverse_conflict(self): + """ + If a dict exists and a value is to be added, add it as blank key + """ + d = {'a': 1, 'x': {'y': 2}} + set_value(d, ['x'], 3) + assert d == {'a': 1, 'x': {'y': 2, '': 3}} + + def test_overwrite_conflict(self): + """ + If a newer final value comes, replace with the older + """ + d = {'a': 1, 'x': 2} + set_value(d, ['x'], 3) + assert d == {'a': 1, 'x': 3}