mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Merge b6df77f280
into 50749c4730
This commit is contained in:
commit
7287b27a8d
|
@ -322,16 +322,6 @@ class Field(object):
|
|||
Called when a field is added to the parent serializer instance.
|
||||
"""
|
||||
|
||||
# In order to enforce a consistent style, we error if a redundant
|
||||
# 'source' argument has been used. For example:
|
||||
# my_field = serializer.CharField(source='my_field')
|
||||
assert self.source != field_name, (
|
||||
"It is redundant to specify `source='%s'` on field '%s' in "
|
||||
"serializer '%s', because it is the same as the field name. "
|
||||
"Remove the `source` keyword argument." %
|
||||
(field_name, self.__class__.__name__, parent.__class__.__name__)
|
||||
)
|
||||
|
||||
self.field_name = field_name
|
||||
self.parent = parent
|
||||
|
||||
|
|
|
@ -65,14 +65,6 @@ class RelatedField(Field):
|
|||
self.queryset = kwargs.pop('queryset', self.queryset)
|
||||
self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
|
||||
self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
|
||||
assert self.queryset is not None or kwargs.get('read_only', None), (
|
||||
'Relational field must provide a `queryset` argument, '
|
||||
'or set read_only=`True`.'
|
||||
)
|
||||
assert not (self.queryset is not None and kwargs.get('read_only', None)), (
|
||||
'Relational fields should not provide a `queryset` argument, '
|
||||
'when setting read_only=`True`.'
|
||||
)
|
||||
kwargs.pop('many', None)
|
||||
kwargs.pop('allow_empty', None)
|
||||
super(RelatedField, self).__init__(**kwargs)
|
||||
|
|
|
@ -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