在Django Rest Framework中向序列化器类传递额外参数

109 投票
8 回答
110944 浏览
提问于 2025-04-18 02:11

我想从视图(Viewset)给DRF的序列化器(Serializer)类传递一些参数,所以我尝试了这个:

class OneZeroSerializer(rest_serializer.ModelSerializer):

    def __init__(self, *args, **kwargs):
        print args # show values that passed

    location = rest_serializer.SerializerMethodField('get_alternate_name')

    def get_alternate_name(self, obj):
        return ''


    class Meta:
        model = OneZero

        fields = ('id', 'location')

视图

class OneZeroViewSet(viewsets.ModelViewSet):

   serializer_class = OneZeroSerializer(realpart=1)
   #serializer_class = OneZeroSerializer

   queryset = OneZero.objects.all()

基本上,我想根据查询字符串的值,从视图传递一些信息到序列化器类,然后这些信息会被分配到字段上。

这些字段实际上并不在模型中,而是动态创建的字段。

这个问题和stackoverflow上的一个问题类似,但我看不懂那个答案。

有没有人能帮我解决这个问题,或者给我更好的建议呢?

8 个回答

1

如果你的查询是一个元素列表,下面是元素的列表:

my_data = DataSerializers(queryset_to_investigate, 
                          many=True, context={'value_to_pass': value_passed}

如果是单个数据查询,情况如下:

my_data = DataSerializers(queryset_to_investigate, 
                          context={'value_to_pass': value_passed}

接下来在序列化器中:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        fields = '__all__'
        model = 'Name_of_your_model'

    def on_representation(self, value):
        serialized_data = super(MySerializer, self).to_representation(value)
        value_as_passed = self.context['value_to_pass']
        # ..... do all you need ......
        return serialized_data

如你所见,在on_representation里面打印self,你会看到:query_set: <object (x)>, context={'value_to_pass': value_passed}

这是一种更简单的方法,你可以在任何包含self作为参数的序列化器函数中使用这个方法。

14

这是我以前写的一段老代码,可能对你们有帮助——用来过滤嵌套的序列化器:

class MySerializer(serializers.ModelSerializer):

    field3  = serializers.SerializerMethodField('get_filtered_data')

    def get_filtered_data(self, obj):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            try:
                data = Other_model.objects.get(pk_field=obj, filter_field=param_value)
            except:
                return None
            serializer = OtherSerializer(data)
            return serializer.data
        else:
            print "Error stuff"

    class Meta:
        model = Model_name
        fields = ('filed1', 'field2', 'field3')

如何重写 get_serializer_class 方法:

class ViewName(generics.ListAPIView):

    def get_serializer_class(self):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            return Serializer1
        else:
            return Serializer2

    def get_queryset(self):
       .....

希望这能帮助到正在寻找这个的人。

29

为了回答redcyb的问题,可以考虑在你的视图中使用GenericAPIView里的get_serializer_context方法,像这样:

def get_serializer_context(self):
    return {'user': self.request.user.email}
52

你可以在 YourView 里重写 get_serializer_context 这个方法,像这样:

class YourView(GenericAPIView):

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context["customer_id"] = self.kwargs['customer_id']
        context["query_params"] = self.request.query_params
        return context

或者这样:

class YourView(GenericAPIView):
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        serializer.context["customer_id"] = request.user.id
        serializer.context["query_params"] = request.query_params

        serializer.is_valid(raise_exception=True)
        ...

然后在你的序列化器的任何地方都可以获取到它。比如在一个自定义的方法里:

class YourSerializer(ModelSerializer):
    def get_alternate_name(self, obj):
        customer_id = self.context["customer_id"]
        query_params = self.context["query_params"]
        ...
154

使用“context”参数来创建“ModelSerializer”非常简单。

比如说:

在视图中:

my_objects = MyModelSerializer(
    input_collection, 
    many=True, 
    context={'user_id': request.user.id}
).data

在序列化器中:

class MyModelSerializer(serializers.ModelSerializer):
...

    is_my_object = serializers.SerializerMethodField('_is_my_find')
...

    def _is_my_find(self, obj):
        user_id = self.context.get("user_id")
        if user_id:
            return user_id in obj.my_objects.values_list("user_id", flat=True)
        return False
...

这样你就可以用“self.context”来获取额外的参数了。

参考链接

撰写回答