Skip to content

Commit a73c16b

Browse files
committed
serializers.Field respects ordering on dicts if it exists. Closes encode#832
1 parent b950b02 commit a73c16b

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

rest_framework/fields.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from django.forms import widgets
2020
from django.utils.encoding import is_protected_type
2121
from django.utils.translation import ugettext_lazy as _
22+
from django.utils.datastructures import SortedDict
2223

2324
from rest_framework import ISO_8601
2425
from rest_framework.compat import timezone, parse_date, parse_datetime, parse_time
@@ -170,7 +171,11 @@ def to_native(self, value):
170171
elif hasattr(value, '__iter__') and not isinstance(value, (dict, six.string_types)):
171172
return [self.to_native(item) for item in value]
172173
elif isinstance(value, dict):
173-
return dict(map(self.to_native, (k, v)) for k, v in value.items())
174+
# Make sure we preserve field ordering, if it exists
175+
ret = SortedDict()
176+
for key, val in value.items():
177+
ret[key] = self.to_native(val)
178+
return ret
174179
return smart_text(value)
175180

176181
def attributes(self):

rest_framework/tests/fields.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
General serializer field tests.
33
"""
44
from __future__ import unicode_literals
5+
from django.utils.datastructures import SortedDict
56
import datetime
67
from decimal import Decimal
7-
88
from django.db import models
99
from django.test import TestCase
1010
from django.core import validators
11-
1211
from rest_framework import serializers
1312
from rest_framework.serializers import Serializer
1413

@@ -63,6 +62,20 @@ def test_non_auto_pk_fields_not_read_only(self):
6362
serializer = CharPrimaryKeyModelSerializer()
6463
self.assertEqual(serializer.fields['id'].read_only, False)
6564

65+
def test_dict_field_ordering(self):
66+
"""
67+
Field should preserve dictionary ordering, if it exists.
68+
See: https://github.com/tomchristie/django-rest-framework/issues/832
69+
"""
70+
ret = SortedDict()
71+
ret['c'] = 1
72+
ret['b'] = 1
73+
ret['a'] = 1
74+
ret['z'] = 1
75+
field = serializers.Field()
76+
keys = list(field.to_native(ret).keys())
77+
self.assertEqual(keys, ['c', 'b', 'a', 'z'])
78+
6679

6780
class DateFieldTest(TestCase):
6881
"""
@@ -645,4 +658,4 @@ class DecimalSerializer(Serializer):
645658
s = DecimalSerializer(data={'decimal_field': '12345.6'})
646659

647660
self.assertFalse(s.is_valid())
648-
self.assertEqual(s.errors, {'decimal_field': ['Ensure that there are no more than 4 digits in total.']})
661+
self.assertEqual(s.errors, {'decimal_field': ['Ensure that there are no more than 4 digits in total.']})

0 commit comments

Comments
 (0)