扩展django rest框架以允许在嵌套序列化程序中继承上下文

o_c*_*o_c 8 django serialization python-2.7 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
Run Code Online (Sandbox Code Playgroud)

但随后发现从'get_entities'传递给'InstituteSerializer'的'context'不会传递给嵌套的序列化器.这意味着在上面的例子中 - InstituteSerializer在'context'中有'basic_view',但是MemberSerializer和DepartmentSerializer没有.

在嵌套序列化器django rest框架的上下文中找到了一个工作解决方案:每个嵌套字段使用SerializerMethodField(例如'departments'),并在'get_'方法中手动传递上下文.我的解决方案的问题是它需要在我的代码中嵌入此代码20-30次,最终使源代码行数量增加一倍.

我的请求 - 如果有人(或可以帮助实现)serializers.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')
Run Code Online (Sandbox Code Playgroud)

o_c*_*o_c 9

显然我错过了一些东西......"上下文" 已经被继承到嵌套的序列化器......

但是,它对我不起作用的原因是因为作为我的嵌套的一部分,一些子序列化器是通过serializers.SerializerMethodField()定义的.在这种情况下(仅!),上下文不会自动继承.

解决方案是在与每个SerializerMethodField相关的'get _...'方法中简单地传递'context':

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

    def get_child(self, obj):
        child = ....
        serializer = ChildSerializer(instance=child, context=self.context)
        return serializer.data
Run Code Online (Sandbox Code Playgroud)

PS - 与我的类似的DRF github问题是在不久前创建的:https://github.com/tomchristie/django-rest-framework/issues/2555