Skip to content

Commit 9984fa2

Browse files
committed
Fix serializer multiple inheritance bug
1 parent cf2442d commit 9984fa2

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

rest_framework/serializers.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,22 @@ def _get_declared_fields(cls, bases, attrs):
299299
if isinstance(obj, Field)]
300300
fields.sort(key=lambda x: x[1]._creation_counter)
301301

302-
# If this class is subclassing another Serializer, add that Serializer's
303-
# fields. Note that we loop over the bases in *reverse*. This is necessary
304-
# in order to maintain the correct order of fields.
305-
for base in reversed(bases):
306-
if hasattr(base, '_declared_fields'):
307-
fields = [
308-
(field_name, obj) for field_name, obj
309-
in base._declared_fields.items()
310-
if field_name not in attrs
311-
] + fields
312-
313-
return OrderedDict(fields)
302+
# Ensures a base class field doesn't override cls attrs, and maintains
303+
# field precedence when inheriting multiple parents. e.g. if there is a
304+
# class C(A, B), and A and B both define 'field', use 'field' from A.
305+
known = set(attrs)
306+
307+
def visit(name):
308+
known.add(name)
309+
return name
310+
311+
base_fields = [
312+
(visit(name), f)
313+
for base in bases if hasattr(base, '_declared_fields')
314+
for name, f in base._declared_fields.items() if name not in known
315+
]
316+
317+
return OrderedDict(base_fields + fields)
314318

315319
def __new__(cls, name, bases, attrs):
316320
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)

0 commit comments

Comments
 (0)