将额外的参数传递给 Django Rest Framework 中的序列化程序类

Posted

技术标签:

【中文标题】将额外的参数传递给 Django Rest Framework 中的序列化程序类【英文标题】:Pass extra arguments to Serializer Class in Django Rest Framework 【发布时间】:2014-05-24 05:01:26 【问题描述】:

我想从 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()

基本上我想将一些基于查询字符串的值从视图传递到序列化器类,然后这些值将分配给字段。

这些字段实际上不包含在模型中动态创建的字段。

这个问题***的情况相同,但我无法理解答案。

任何人都可以在这种情况下帮助我或建议我更好的选择。

【问题讨论】:

@PauloScardine 你能给我提供简单的例子或任何我可以得到帮助的链接吗?我是 django 新手,所以听不懂你的话。 你提到的问题的答案是对的,去阅读get_serializer方法的文档并重写它以返回一个自定义的序列化器实例。 Dynamically modifying serializer fields in Django Rest Framework的可能重复 我也提到了这个问题作为参考,但没有任何细节可以帮助我 我已阅读文档,但找不到任何传递额外参数的示例。只有示例如何使用不同的序列化类。这就是为什么我在这里发布问题 【参考方案1】:

“ModelSerializer”构造函数的“context”arg 非常简单。

例如:

在视图中:

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”来获取额外的参数。

Reference

【讨论】:

这不起作用..当我在序列化程序中传递带有额外字段的上下文时,这个额外的字段丢失并且上下文看起来像:'request': <rest_framework.request.Request object at 0x103a2ba20>, 'view': <api.views.CourseAssignmentViewSet object at 0x10326b828>, 'format': None @redcyb 你能帮我解决这个问题吗***.com/questions/62039305/…【参考方案2】:

您可以在 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)
        ...

anywhere 在您的序列化程序中,您可以获得它。例如在自定义方法中:

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

【讨论】:

你能帮我解决这个问题吗***.com/questions/62039305/… @banky,我在***.com/a/62040334/6077223下方添加了评论 拯救了我的一天!这个找了好久【参考方案3】:

要实现 redcyb 的答案 - 考虑在您的视图中使用来自 GenericAPIViewget_serializer_context 方法,如下所示:

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

【讨论】:

只覆盖get_serializer_context 不会削减它,因为validated_data 使用上下文更新的真实位置是serializer.save() 方法,由ViewSet.update() -> ViewSet.perform_update()ViewSet.create() -> ViewSet.perform_create() 调用。但问题是他们没有将**kwargs 与上下文一起传递给save()。因此,为了混合上下文,我们必须覆盖 perform_createperform_update 以便它们将上下文传递给 save() @andilabs 你能帮我解决这个问题吗? ***.com/questions/62039305/…【参考方案4】:

我写的一个旧代码,可能对过滤嵌套序列化程序有帮助:

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):
       .....

希望这有助于人们寻找这个。

【讨论】:

正是我获取查询参数所需要的,谢谢!请注意,显示的代码已被弃用。要获取参数值,它现在看起来像 self.context['request'].query_params.get()【参考方案5】:

如果您的查询是元素列表,则为元素列表:

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 中打印自我,您可以看到:query_set: <object (x)>, context='value_to_pass': value_passed

这是一种更简单的方法,您可以在参数列表中包含 self 的序列化器的任何函数中执行此操作。

【讨论】:

【参考方案6】:

这些答案远非复杂;如果您有任何类型的身份验证,则将此属性添加到您的序列化程序并调用它以访问发送请求的用户。

类 BaseSerializer(serializers.ModelSerializer):

@property
def sent_from_user(self):
    return self.context['request'].user

【讨论】:

以上是关于将额外的参数传递给 Django Rest Framework 中的序列化程序类的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将参数传递给基于类的视图测试 Django Rest Framework?

将额外参数传递给事件处理程序?

将额外的参数传递给回调函数

如何将额外的额外参数传递给批处理文件?

将多个参数传递给rest API - Spring

将额外的参数传递给IntersectionObserver?