Расширьте Django Rest framework, чтобы разрешить наследование контекста во вложенных сериализаторах

Я использую Django 1.6 (очень скоро обновление до 1.8), Python 2.7 и DRF 3.2.5 (очень скоро обновление до последней версии).

у меня есть набор вложенных сериализаторы (~10 уровней, в общей сложности 20-30 моделей, которые сериализуются). Я пытаюсь добавить логический флаг в контекст, который определит, будет ли сериализованная выходная иерархия детализирована (включая поля всех моделей) или базовая (только часть полей).

Я написал следующий код (частичное фрагмент):

from rest_framework import serializers
from app.models import Institute, Department, Member

class MemberSerializer(serializers.ModelSerializer):
    def get_fields(self):
        fields = super(MemberSerializer, self).get_fields()
        if self.context['basic_view']:
            for field in ['height', 'weight']:
                del fields[field]
        return fields

    class Meta:
        model = Member
        fields = ('id', 'birth_date', 'height', 'weight')


class DepartmentSerializer(serializers.ModelSerializer):
    members = MemberSerializer(many=True, read_only=True)

    def get_fields(self):
        fields = super(DepartmentSerializer, self).get_fields()
        if self.context['basic_view']:
            for field in ['type', 'manager']:
                del fields[field]
        return fields

    class Meta:
        model = Department
        fields = ('id', 'name', 'type', 'manager', 'members')


class InstituteSerializer(serializers.ModelSerializer):
    departments = DepartmentSerializer(many=True, read_only=True)

    def get_fields(self):
        fields = super(InstituteSerializer, self).get_fields()
        if self.context['basic_view']:
            for field in ['name', 'type']:
                del fields[field]
        return fields

    class Meta:
        model = Institute
        fields = ('id', 'name', 'type', 'departments')

def get_entities(is_basic_view):
    institutes_list = Institute.objects.all()

    serializer = InstituteSerializer(institutes_list, many=True, read_only=True, context={'basic_view': is_basic_view})

    return serializer.data

но затем выяснилось, что "контекст", который передается из "get_entities" в "InstituteSerializer", не передается вложенным сериализаторам. Это означает, что в приведенном выше примере - InstituteSerializer имеет "basic_view" в "контексте", но MemberSerializer & DepartmentSerializer нет.

Я нашел рабочее решение в контекст во вложенных сериализаторах django Rest framework: использовать SerializerMethodField для каждого вложенного поля (например 'departments'), и в методе 'get_' вручную передать контекст. Моя проблема с этим решением заключается в том, что он требует встраивания этого кода 20-30 раз в мой код, в конечном итоге удваивая количество исходных строк.

мой запрос-если у кого-то есть (или может помочь реализовать) расширение для сериализаторов.ModelSerializer, который получит дополнительный параметр при построении, например "inherit_context". Тогда единственное, что мне нужно будет изменить в моих классах, например в "InstituteSerializer", является добавлением этого параметра:

class InstituteSerializer(serializers.ModelSerializer):
    departments = DepartmentSerializer(many=True, read_only=True, inherit_context=True)

    def get_fields(self):
        fields = super(InstituteSerializer, self).get_fields()
        if self.context['basic_view']:
            for field in ['name', 'type']:
                del fields[field]
        return fields

    class Meta:
        model = Institute
        fields = ('id', 'name', 'type', 'departments')

1 ответов


видимо я что-то пропустил... "Контекст"уже унаследовал вплоть до вложенных сериализаторов...

однако, причина, по которой это не сработало для меня, заключается в том, что в рамках моего вложенности некоторые из дочерних сериализаторов были определены через сериализаторы.SerializerMethodField(). И в таком случае (только!) контекст не автоматически наследуется.

решение состоит в том, чтобы просто передать "контекст", внутри в 'get_...'метод, связанный с каждым SerializerMethodField:

class ParentSerializer(serializers.ModelSerializer):
    child = serializers.SerializerMethodField()

    def get_child(self, obj):
        child = ....
        serializer = ChildSerializer(instance=child, context=self.context)
        return serializer.data

P. S-проблема DRF github, подобная моей, была создана некоторое время назад:https://github.com/tomchristie/django-rest-framework/issues/2555