mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Fix serializer multiple inheritance bug (#6980)
* Expand declared filtering tests - Test declared filter ordering - Test multiple inheritance * Fix serializer multiple inheritance bug * Improve field order test to check for field types
This commit is contained in:
parent
7c5459626d
commit
b8c369c4cf
|
@ -298,18 +298,22 @@ class SerializerMetaclass(type):
|
|||
if isinstance(obj, Field)]
|
||||
fields.sort(key=lambda x: x[1]._creation_counter)
|
||||
|
||||
# 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.
|
||||
for base in reversed(bases):
|
||||
if hasattr(base, '_declared_fields'):
|
||||
fields = [
|
||||
(field_name, obj) for field_name, obj
|
||||
in base._declared_fields.items()
|
||||
if field_name not in attrs
|
||||
] + fields
|
||||
# Ensures a base class field doesn't override cls attrs, and maintains
|
||||
# field precedence when inheriting multiple parents. e.g. if there is a
|
||||
# class C(A, B), and A and B both define 'field', use 'field' from A.
|
||||
known = set(attrs)
|
||||
|
||||
return OrderedDict(fields)
|
||||
def visit(name):
|
||||
known.add(name)
|
||||
return name
|
||||
|
||||
base_fields = [
|
||||
(visit(name), f)
|
||||
for base in bases if hasattr(base, '_declared_fields')
|
||||
for name, f in base._declared_fields.items() if name not in known
|
||||
]
|
||||
|
||||
return OrderedDict(base_fields + fields)
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
|
||||
|
|
|
@ -682,3 +682,53 @@ class TestDeclaredFieldInheritance:
|
|||
assert len(Parent().get_fields()) == 2
|
||||
assert len(Child().get_fields()) == 2
|
||||
assert len(Grandchild().get_fields()) == 2
|
||||
|
||||
def test_multiple_inheritance(self):
|
||||
class A(serializers.Serializer):
|
||||
field = serializers.CharField()
|
||||
|
||||
class B(serializers.Serializer):
|
||||
field = serializers.IntegerField()
|
||||
|
||||
class TestSerializer(A, B):
|
||||
pass
|
||||
|
||||
fields = {
|
||||
name: type(f) for name, f
|
||||
in TestSerializer()._declared_fields.items()
|
||||
}
|
||||
assert fields == {
|
||||
'field': serializers.CharField,
|
||||
}
|
||||
|
||||
def test_field_ordering(self):
|
||||
class Base(serializers.Serializer):
|
||||
f1 = serializers.CharField()
|
||||
f2 = serializers.CharField()
|
||||
|
||||
class A(Base):
|
||||
f3 = serializers.IntegerField()
|
||||
|
||||
class B(serializers.Serializer):
|
||||
f3 = serializers.CharField()
|
||||
f4 = serializers.CharField()
|
||||
|
||||
class TestSerializer(A, B):
|
||||
f2 = serializers.IntegerField()
|
||||
f5 = serializers.CharField()
|
||||
|
||||
fields = {
|
||||
name: type(f) for name, f
|
||||
in TestSerializer()._declared_fields.items()
|
||||
}
|
||||
|
||||
# `IntegerField`s should be the 'winners' in field name conflicts
|
||||
# - `TestSerializer.f2` should override `Base.F2`
|
||||
# - `A.f3` should override `B.f3`
|
||||
assert fields == {
|
||||
'f1': serializers.CharField,
|
||||
'f2': serializers.IntegerField,
|
||||
'f3': serializers.IntegerField,
|
||||
'f4': serializers.CharField,
|
||||
'f5': serializers.CharField,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user