将请求上下文从 Django Rest Framework 中的 Viewset 传递给序列化程序

Posted

技术标签:

【中文标题】将请求上下文从 Django Rest Framework 中的 Viewset 传递给序列化程序【英文标题】:Pass request context to serializer from Viewset in Django Rest Framework 【发布时间】:2015-09-11 08:59:52 【问题描述】:

我有一种情况,序列化器字段的值取决于当前登录用户的身份。我已经看到了如何在初始化序列化程序时将用户添加到上下文中,但我不确定在使用 ViewSet 时如何执行此操作,因为您只提供序列化程序类而不是实际的序列化程序实例。

基本上我想知道如何去:

class myModelViewSet(ModelViewSet):
   queryset = myModel.objects.all()
   permission_classes = [DjangoModelPermissions]
   serializer_class = myModelSerializer

到:

class myModelSerializer(serializers.ModelSerializer):
    uploaded_by = serializers.SerializerMethodField()
    special_field = serializers.SerializerMethodField()

    class Meta:
        model = myModel

    def get_special_field(self, obj):
        if self.context['request'].user.has_perm('something.add_something'):
           return something

抱歉,如果不清楚,来自 DOC: Adding Extra Context 哪个说要做

serializer = AccountSerializer(account, context='request': request)
serializer.data

但我不确定如何从视图集中自动执行此操作,因为我只能更改序列化程序类,而不是序列化程序实例本身。

【问题讨论】:

你试过self.context.get('request').user.has_perm("some.permission")吗? 您希望something 在输出中与序列化程序的其他字段一起返回吗? 对不起,如果不清楚,问题是 self.context 在序列化程序中是空的。 AccountSerializer(account, context='request': request) 是我所需要的一切 citynorman 你在哪里定义请求?我尝试将请求定义为:context='request': 'user': self.admins[0].user ,但它不起作用! 【参考方案1】:

GenericViewSet 具有 get_serializer_context 方法,可以让您更新 context

class myModelViewSet(ModelViewSet):
    queryset = myModel.objects.all()
    permission_classes = [DjangoModelPermissions]
    serializer_class = myModelSerializer

    def get_serializer_context(self):
        context = super(myModelViewSet, self).get_serializer_context()
        context.update("request": self.request)
        return context

【讨论】:

选择这个作为最佳答案。我相信这会解决我的问题(如果这实际上是我的问题)。结果我错过了在这种情况下我手动实例化序列化程序的事实,并且它没有被视图集路由。哦。 对我来说:NameError: name 'request' is not defined @Coderaemon 你解决了吗?这就是我得到的:/上下文没有传递给序列化程序 最新的 DRF 在发送到序列化程序的默认上下文中包含self.request;你不需要手动添加它。 对于每个收到请求的人 KeyError:您可以通过使用请求对象从视图初始化序列化程序来解决此问题,如下所示:serializer = serializers.RandomSerializer(data=request.data, context= 'request':request) 来源:django-rest-framework.org/api-guide/serializers/…【参考方案2】:

在覆盖函数get_serializer_context 中返回父上下文将使访问请求及其数据变得容易。

 class myModelViewSet(ModelViewSet):
       queryset = myModel.objects.all()
       permission_classes = [DjangoModelPermissions]
       serializer_class = myModelSerializer

       def get_serializer_context(self):
       """
       pass request attribute to serializer
       """
           context = super(myModelViewSet, self).get_serializer_context()
           return context

这非常稳定,因为每次我们请求视图集时,它都会返回上下文。

【讨论】:

【参考方案3】:

序列化器字段的值取决于当前登录用户的身份

这就是我在 ModelViewSet 中处理此类情况的方式:

def perform_create(self, serializer):

    user = self.request.user
    if user.username == 'myuser':
        serializer.data['myfield'] = 'something'

    serializer.save()

【讨论】:

【参考方案4】:

只需在视图集中使用 get_serializer()

def get_serializer(self, *args, **kwargs):
    """
    Return the serializer instance that should be used for validating and
    deserializing input, and for serializing output.
    """
    serializer_class = self.get_serializer_class()
    kwargs['context'] = self.get_serializer_context()
    return serializer_class(*args, **kwargs)

【讨论】:

你的 ViewSet 应该是 GenericViewSet 的子类【参考方案5】:

对于基于功能的视图,您可以按如下方式传递请求或用户:

serializer = ProductSerializer(context = 'request':request,data=request.data)

您的序列化程序可能如下所示:

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model    = Product
        fields   = ['id']

    def create(self, validated_data):
        user =  self.context['request'].user
        print("User is")
        print(user)

如果有更好的方法,请随时告知。

【讨论】:

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

Django Rest Frame API:ModelSerializer 中的附加字段

如何解决 django rest-framework 中的错误请求

我需要显示与相同模型有多对多关系的相关字段。 Django Rest Frame工作

Django REST框架-请求与响应

Django REST Framework:序列化程序上下文如何工作?

如何使用 Axios 将 CSRF Coo​​kie 从 React 发送到 Django Rest Framework