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

Pass request context to serializer from Viewset in Django Rest Framework

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

基本上我想知道如何去:

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

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

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

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

GenericViewSetget_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

Return 覆盖函数 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

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

the values for a serializer field depend on the identity of the currently logged in user

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

def perform_create(self, serializer):

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

    serializer.save()

只需在您的视图集中使用 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)

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

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)

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

只需在您的 class 中添加这 2 行方法即可。

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

由于发布的答案有部分正确性,为了完整性起见在此进行总结。

  1. 覆盖 get_serializer_context..AND
  2. 在您的视图中使用 get_serializer 而不是手动调用序列化程序