mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Add support for overriding fields in serializer subclasses.
This is an updated version of tomchristie/django-rest-framework#1053 applied to current master.
This commit is contained in:
parent
69dfb5d818
commit
3747e9baa8
|
@ -280,11 +280,19 @@ class SerializerMetaclass(type):
|
|||
# If this class is subclassing another Serializer, add that Serializer's
|
||||
# fields. Note that we loop over the bases in *reverse*. This is necessary
|
||||
# in order to maintain the correct order of fields.
|
||||
all_fields = OrderedDict()
|
||||
for base in reversed(bases):
|
||||
if hasattr(base, '_declared_fields'):
|
||||
fields = list(base._declared_fields.items()) + fields
|
||||
for name, field in base._declared_fields.items():
|
||||
if name in all_fields:
|
||||
# Throw away old ordering, then replace with new one
|
||||
all_fields.pop(name)
|
||||
all_fields[name] = field
|
||||
|
||||
return OrderedDict(fields)
|
||||
# if there are fields in both base_fields and fields, OrderedDict
|
||||
# uses the *last* one defined. So fields needs to go last.
|
||||
all_fields.update(OrderedDict(fields))
|
||||
return all_fields
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
|
||||
|
|
|
@ -309,3 +309,85 @@ class TestCacheSerializerData:
|
|||
pickled = pickle.dumps(serializer.data)
|
||||
data = pickle.loads(pickled)
|
||||
assert data == {'field1': 'a', 'field2': 'b'}
|
||||
|
||||
|
||||
class TestSerializerSupportsOverriddenFields:
|
||||
def setup(self):
|
||||
class Base1(serializers.Serializer):
|
||||
a_field = serializers.CharField()
|
||||
self.Base1 = Base1
|
||||
|
||||
class Base2(serializers.Serializer):
|
||||
a_field = serializers.IntegerField()
|
||||
self.Base2 = Base2
|
||||
|
||||
def test_base_fields_unchanged(self):
|
||||
"""
|
||||
Overriding a field in a subclassed serializer shouldn't change the
|
||||
field on the superclass
|
||||
"""
|
||||
class OverriddenFields(self.Base1):
|
||||
a_field = serializers.FloatField()
|
||||
|
||||
assert isinstance(
|
||||
self.Base1._declared_fields['a_field'],
|
||||
serializers.CharField,
|
||||
)
|
||||
s = self.Base1()
|
||||
assert isinstance(s.fields['a_field'], serializers.CharField)
|
||||
|
||||
def test_overridden_fields_single_base(self):
|
||||
"""
|
||||
Subclassing a serializer and overriding a field should mean the field
|
||||
on the subclass wins.
|
||||
"""
|
||||
class OverriddenFieldsWithSingleBase(self.Base1):
|
||||
a_field = serializers.FloatField()
|
||||
|
||||
assert isinstance(
|
||||
OverriddenFieldsWithSingleBase._declared_fields['a_field'],
|
||||
serializers.FloatField,
|
||||
)
|
||||
s = OverriddenFieldsWithSingleBase()
|
||||
assert isinstance(s.fields['a_field'], serializers.FloatField)
|
||||
|
||||
def test_overridden_fields_multiple_bases(self):
|
||||
"""
|
||||
For serializers with multiple bases, the field on the first base wins
|
||||
(as per normal python method resolution order)
|
||||
"""
|
||||
class OverriddenFieldsMultipleBases1(self.Base1, self.Base2):
|
||||
# first base takes precedence; a_field should be a CharField.
|
||||
pass
|
||||
|
||||
assert isinstance(
|
||||
OverriddenFieldsMultipleBases1._declared_fields['a_field'],
|
||||
serializers.CharField,
|
||||
)
|
||||
s = OverriddenFieldsMultipleBases1()
|
||||
assert isinstance(s.fields['a_field'], serializers.CharField)
|
||||
|
||||
class OverriddenFieldsMultipleBases2(self.Base2, self.Base1):
|
||||
# first base takes precedence; a_field should be a IntegerField.
|
||||
pass
|
||||
|
||||
assert isinstance(
|
||||
OverriddenFieldsMultipleBases2._declared_fields['a_field'],
|
||||
serializers.IntegerField,
|
||||
)
|
||||
s = OverriddenFieldsMultipleBases2()
|
||||
assert isinstance(s.fields['a_field'], serializers.IntegerField)
|
||||
|
||||
def test_overridden_fields_multiple_bases_overridden(self):
|
||||
"""
|
||||
For serializers with multiple bases, locally defined fields still win.
|
||||
"""
|
||||
class OverriddenFieldsMultipleBasesOverridden(self.Base1, self.Base2):
|
||||
a_field = serializers.FloatField()
|
||||
|
||||
assert isinstance(
|
||||
OverriddenFieldsMultipleBasesOverridden._declared_fields['a_field'],
|
||||
serializers.FloatField,
|
||||
)
|
||||
s = OverriddenFieldsMultipleBasesOverridden()
|
||||
assert isinstance(s.fields['a_field'], serializers.FloatField)
|
||||
|
|
Loading…
Reference in New Issue
Block a user