mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-27 16:40:03 +03:00
Better handle conflicting keys in set_values
This commit adds logic to set_values to move values on keys to be added upon to a blank key inside the value's previous key. This would allow constructions like: ``` fk_object = HyperlinkedRelatedField(source='fk') fk_name = CharField('fk.field') ``` Tests are also added specifically for set_values with the examples given in the function description as well as for this change.
This commit is contained in:
parent
8351747d98
commit
9b33778667
|
@ -125,9 +125,14 @@ def set_value(dictionary, keys, value):
|
||||||
for key in keys[:-1]:
|
for key in keys[:-1]:
|
||||||
if key not in dictionary:
|
if key not in dictionary:
|
||||||
dictionary[key] = {}
|
dictionary[key] = {}
|
||||||
|
elif type(dictionary[key]) is not dict:
|
||||||
|
dictionary[key] = {'': dictionary[key]}
|
||||||
dictionary = 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):
|
def to_choices_dict(choices):
|
||||||
|
|
|
@ -14,7 +14,7 @@ from django.utils.timezone import activate, deactivate, override, utc
|
||||||
import rest_framework
|
import rest_framework
|
||||||
from rest_framework import exceptions, serializers
|
from rest_framework import exceptions, serializers
|
||||||
from rest_framework.fields import (
|
from rest_framework.fields import (
|
||||||
BuiltinSignatureError, DjangoImageField, is_simple_callable
|
BuiltinSignatureError, DjangoImageField, is_simple_callable, set_value
|
||||||
)
|
)
|
||||||
|
|
||||||
# Tests for helper functions.
|
# Tests for helper functions.
|
||||||
|
@ -2380,3 +2380,65 @@ class TestValidationErrorCode:
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 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}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user