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

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

抱歉,医生说得不够清楚: 添加额外上下文 也就是说

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

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

81512 次浏览

GenericViewSet has the get_serializer_context method which will let you update context:

class MyModelViewSet(ModelViewSet):
queryset = MyModel.objects.all()
permission_classes = [DjangoModelPermissions]
serializer_class = MyModelSerializer


def get_serializer_context(self):
context = super().get_serializer_context()
context.update({"request": self.request})
return context

For Python 2.7, use context = super(MyModelViewSet, self).get_serializer_context()

Return parent context in overrided function get_serializer_context will make it easy to access request and its data.

 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

This is very stable as every time we request viewset, it returns context as well.

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

This is how I handle such cases in my ModelViewSet:

def perform_create(self, serializer):


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


serializer.save()

just use get_serializer() in your viewsets

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)

For Function based views you can pass request or user as follow:

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

Your Serializer may look like:

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)

Feel free to inform if there is any better way to do this.

Simply add this 2 line method in your class and you are good to go.

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

since the posted answers had partial correctness, summarizing here in the interest of completeness.

  1. override get_serializer_context..AND
  2. use get_serializer in your views instead of manually calling the serializer