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


76

我有一种情况,其中序列化器字段的值取决于当前登录用户的身份。我已经看到了在初始化序列化程序时如何将用户添加到上下文中,但是我不确定在使用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: 添加额外的上下文 说明

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

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


2
你试过了self.context.get('request').user.has_perm("some.permission")吗?
Ugur 2015年

是否要something在输出中与序列化程序的其他字段一起返回?
Animesh Sharma 2015年

抱歉,如果不清楚,问题在于序列化程序中的self.context为空。
oowowaee 2015年

1
AccountSerializer(account, context={'request': request})是我所需要的一切
citynorman

您在哪里定义请求?我尝试将请求定义为:context={'request': { 'user': self.admins[0].user }}并且不起作用!
joseglego '20

Answers:


103

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

选择此作为最佳答案。我相信这可以解决我的问题(如果这实际上是我的问题)。事实证明,在这种情况下,我错过了手动实例化序列化程序的事实,并且没有被视图集路由。天啊
oowowaee 2015年

3
对我来说,它说:NameError: name 'request' is not defined
Coderaemon

1
@Coderaemon您解决了吗?那就是我得到的:/上下文未传递给序列化程序
Brad Reed

20
最新的DRFself.request在默认上下文中包括发送给序列化程序的内容;你不需要手动添加。
亚当

2
对于每个收到请求的人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

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


2

只需在视图集中使用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的子类
steven.yan 16-10-12

0

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

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

def perform_create(self, serializer):

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

    serializer.save()

0

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

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)

随时通知是否有更好的方法可以做到这一点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.