2024年DRF父序列化器向子序列化器传递上下文失败求助
Django REST Framework嵌套序列化器上下文无法传递问题解决
问题描述
我查阅了大量相关讨论,尝试过自定义序列化器、重写父类__init__方法、重写父类to_representation方法等方案,但始终无法将上下文从父序列化器传递到子序列化器。虽然有说法称新版本Django会自动传递上下文,但在我的Django 5.0.2环境中并未生效。
我的业务场景是:序列化Post模型时,调用CommentSerializer序列化关联的评论,需要为每个评论添加user_vote字段,用于判断当前登录用户是否对该评论投过票。父序列化器中可以正常获取到request,但子序列化器的context中request为空。
序列化器代码(Serializers.py)
import sys from rest_framework import serializers from .models import Comment, Post, Vote class CommentSerializer(serializers.ModelSerializer): child_comment = serializers.SerializerMethodField() user_vote = serializers.SerializerMethodField() class Meta: model = Comment fields = '__all__' def get_user_vote(self, obj): # 获取当前请求的用户 print(self.context, file=sys.stderr) user = self.context['request'].user # 检查用户是否对该评论投过票 try: vote = Vote.objects.get(user=user, comment=obj) return vote.value except Vote.DoesNotExist: return 0 class PostSerializerSingle(serializers.ModelSerializer): images = SheetMusicImageSerializer(many=True) comments = CommentSerializer(many=True) class Meta: model = Post fields = '__all__'
解决方案
方案1:通过SerializerMethodField手动传递上下文
修改父序列化器的comments字段,使用SerializerMethodField手动初始化子序列化器并传入当前上下文:
class PostSerializerSingle(serializers.ModelSerializer): images = SheetMusicImageSerializer(many=True) comments = serializers.SerializerMethodField() class Meta: model = Post fields = '__all__' def get_comments(self, obj): # 手动初始化子序列化器并传递父级上下文 return CommentSerializer(obj.comments.all(), many=True, context=self.context).data
方案2:重写父序列化器的to_representation方法
在父序列化器的to_representation方法中,重新处理评论的序列化并传入上下文:
class PostSerializerSingle(serializers.ModelSerializer): images = SheetMusicImageSerializer(many=True) comments = CommentSerializer(many=True) class Meta: model = Post fields = '__all__' def to_representation(self, instance): representation = super().to_representation(instance) # 重新序列化评论并传递上下文 representation['comments'] = CommentSerializer( instance.comments.all(), many=True, context=self.context ).data return representation
方案3:确认视图中序列化器上下文的传递
确保视图中初始化序列化器时正确传递了request上下文(DRF默认会传递,但可以显式确认):
from rest_framework.generics import RetrieveAPIView from .models import Post from .serializers import PostSerializerSingle class PostDetailView(RetrieveAPIView): queryset = Post.objects.all() serializer_class = PostSerializerSingle def get_serializer_context(self): context = super().get_serializer_context() # 显式将request加入上下文 context['request'] = self.request return context
问题原因说明
尽管DRF文档说明嵌套序列化器会自动继承父序列化器的上下文,但在直接声明嵌套序列化器字段(如comments = CommentSerializer(many=True))的场景下,上下文可能没有被正确传递。通过手动初始化子序列化器并传入self.context,可以确保request对象被正确传递到子序列化器中,从而在get_user_vote方法中获取当前用户。
内容的提问来源于stack exchange,提问作者Caden The Yak
相关产品推荐
相关产品推荐

