在Django REST框架序列化程序中动态排除或包含字段

时间:2015-01-14 03:47:17

标签: python django serialization django-rest-framework django-serializer

我在Django REST框架中有一个序列化程序,定义如下:

class QuestionSerializer(serializers.Serializer):
    id = serializers.CharField()
    question_text = QuestionTextSerializer()
    topic = TopicSerializer()

现在我有两个使用上述序列化程序的API视图:

class QuestionWithTopicView(generics.RetrieveAPIView):
    # I wish to include all three fields - id, question_text
    # and topic in this API.
    serializer_class = QuestionSerializer

class QuestionWithoutTopicView(generics.RetrieveAPIView):
    # I want to exclude topic in this API.
    serializer_class = ExamHistorySerializer

一种解决方案是编写两个不同的序列化程序。但是必须有一个更简单的解决方案来有条件地从给定的序列化器中排除一个字段。

4 个答案:

答案 0 :(得分:48)

你有没有尝试过这种技术

class QuestionSerializer(serializers.Serializer):
    def __init__(self, *args, **kwargs):
        remove_fields = kwargs.pop('remove_fields', None)
        super(QuestionSerializer, self).__init__(*args, **kwargs)

        if remove_fields:
            # for multiple fields in a list
            for field_name in remove_fields:
                self.fields.pop(field_name)

class QuestionWithoutTopicView(generics.RetrieveAPIView):
        serializer_class = QuestionSerializer(remove_fields=['field_to_remove1' 'field_to_remove2'])

如果没有,一旦尝试。

答案 1 :(得分:12)

创建新的序列化程序是可行的方法。通过有条件地删除序列化程序中的字段,您将增加额外的复杂性并使您更难以快速诊断代码。你应该尽量避免混合单个职业的责任。

遵循基本的面向对象设计原则是可行的方法。

QuestionWithTopicView 是一个 QuestionWithoutTopicView,但附加了一个字段。

class QuestionSerializer(serializers.Serializer):
        id = serializers.CharField()
        question_text = QuestionTextSerializer()
        topic = TopicSerializer()

class TopicQuestionSerializer(QuestionSerializer):
       topic = TopicSerializer()

答案 2 :(得分:1)

above answer 扩展为更通用的

class QuestionSerializer(serializers.Serializer):
    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)
        super(QuestionSerializer, self).__init__(*args, **kwargs)
        if fields is not None:
            allowed = set(fields.split(','))
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

class QuestionWithoutTopicView(generics.RetrieveAPIView):
    def get_serializer(self, *args, **kwargs):
        kwargs['context'] = self.get_serializer_context()
        fields = self.request.GET.get('display')
        serializer_class = self.get_serializer_class()
        return serializer_class(fields=fields,*args, **kwargs)
    def get_serializer_class(self):
        return QuestionSerializer
    

现在我们可以提供一个名为 display 的查询参数来输出任何自定义显示格式 http://localhost:8000/questions?display=param1,param2

答案 3 :(得分:0)

您可以设置fields的{​​{1}}和exclude属性

这是一个例子:

Meta