This commit is contained in:
Craig de Stigter 2013-08-29 02:51:10 -07:00
commit d3e9159fe7
2 changed files with 89 additions and 2 deletions

View File

@ -109,11 +109,29 @@ def _get_declared_fields(bases, attrs):
# If this class is subclassing another Serializer, add that Serializer's # If this class is subclassing another Serializer, add that Serializer's
# fields. Note that we loop over the bases in *reverse*. This is necessary # fields. Note that we loop over the bases in *reverse*. This is necessary
# in order to maintain the correct order of fields. # in order to maintain the correct order of fields.
# Note: The 'seen' dict here ensures that the fields from the 'first' base
# take precedence over fields from later bases.
# (otherwise SortedDict will squash the first-base field and
# use the field from a later base instead.)
seen = set()
base_fields_map = {}
base_fields_order = []
for base in bases[::-1]: for base in bases[::-1]:
if hasattr(base, 'base_fields'): if hasattr(base, 'base_fields'):
fields = list(base.base_fields.items()) + fields for name, field in base.base_fields.items():
base_fields_map[name] = field
base_fields_order = list(base.base_fields.keys()) + base_fields_order
return SortedDict(fields) seen = set()
base_fields = []
for name in base_fields_order:
if name not in seen:
base_fields.append((name, base_fields_map[name]))
seen.add(name)
# if there are fields in both base_fields and fields, SortedDict
# uses the *last* one defined. So fields needs to go last.
return SortedDict(base_fields + fields)
class SerializerMetaclass(type): class SerializerMetaclass(type):

View File

@ -1643,3 +1643,72 @@ class SerializerSupportsManyRelationships(TestCase):
serializer = SimpleSlugSourceModelSerializer(data={'text': 'foo', 'targets': [1, 2]}) serializer = SimpleSlugSourceModelSerializer(data={'text': 'foo', 'targets': [1, 2]})
self.assertTrue(serializer.is_valid()) self.assertTrue(serializer.is_valid())
self.assertEqual(serializer.data, {'text': 'foo', 'targets': [1, 2]}) self.assertEqual(serializer.data, {'text': 'foo', 'targets': [1, 2]})
### Regression test for #1053
class OverriddenFieldsBase1(serializers.Serializer):
a_field = serializers.CharField()
class OverriddenFieldsBase2(serializers.Serializer):
a_field = serializers.IntegerField()
class OverriddenFieldsWithSingleBase(OverriddenFieldsBase1):
a_field = serializers.FloatField()
class OverriddenFieldsMultipleBases1(OverriddenFieldsBase1, OverriddenFieldsBase2):
# first base takes precedence; a_field should be a CharField.
pass
class OverriddenFieldsMultipleBases2(OverriddenFieldsBase2, OverriddenFieldsBase1):
# first base takes precedence; a_field should be a IntegerField.
pass
class OverriddenFieldsMultipleBasesOverridden(OverriddenFieldsBase1, OverriddenFieldsBase2):
a_field = serializers.FloatField()
class SerializerSupportsOverriddenFields(TestCase):
def test_base_fields_unchanged(self):
self.assertIsInstance(
OverriddenFieldsBase1.base_fields['a_field'],
serializers.CharField,
)
s = OverriddenFieldsBase1()
self.assertIsInstance(s.fields['a_field'], serializers.CharField)
def test_overridden_fields_single_base(self):
self.assertIsInstance(
OverriddenFieldsWithSingleBase.base_fields['a_field'],
serializers.FloatField,
)
s = OverriddenFieldsWithSingleBase()
self.assertIsInstance(s.fields['a_field'], serializers.FloatField)
def test_overridden_fields_multiple_bases(self):
self.assertIsInstance(
OverriddenFieldsMultipleBases1.base_fields['a_field'],
serializers.CharField,
)
s = OverriddenFieldsMultipleBases1()
self.assertIsInstance(s.fields['a_field'], serializers.CharField)
self.assertIsInstance(
OverriddenFieldsMultipleBases2.base_fields['a_field'],
serializers.IntegerField,
)
s = OverriddenFieldsMultipleBases2()
self.assertIsInstance(s.fields['a_field'], serializers.IntegerField)
def test_overridden_fields_multiple_bases_overridden(self):
self.assertIsInstance(
OverriddenFieldsMultipleBasesOverridden.base_fields['a_field'],
serializers.FloatField,
)
s = OverriddenFieldsMultipleBasesOverridden()
self.assertIsInstance(s.fields['a_field'], serializers.FloatField)