如何在Django DRF的ModelSerializer中设置特定QuerySet
解决DRF序列化时过滤关联对象的问题
嘿,我刚好处理过类似的DRF序列化过滤需求,针对你用Django 1.11和DRF 3.8.2的场景,给你两种可行的解决方案,都能实现让PerguntaSerializerModel的respostas字段只返回关联且tipo="alt"的Resposta对象:
方法一:使用SerializerMethodField(简单直接)
这种方式最容易上手,通过自定义序列化字段来过滤关联数据:
首先,先定义好Resposta的基础序列化器:
from rest_framework import serializers from .models import Resposta class RespostaSerializer(serializers.ModelSerializer): class Meta: model = Resposta fields = ('id', 'texto', 'tipo') # 替换成你需要返回的字段
然后修改PerguntaSerializerModel,用SerializerMethodField来替代默认的关联字段序列化:
from .models import Pergunta class PerguntaSerializerModel(serializers.ModelSerializer): # 自定义respostas字段 respostas = serializers.SerializerMethodField() class Meta: model = Pergunta fields = ('id', 'texto', 'respostas') # 加上你的其他字段 def get_respostas(self, obj): # 过滤当前Pergunta关联的tipo为"alt"的Resposta对象 filtered_respostas = obj.respostas.filter(tipo="alt") # 用RespostaSerializer序列化过滤后的结果 return RespostaSerializer(filtered_respostas, many=True).data
这样当你从Questionario级联序列化到Pergunta时,respostas字段就只会返回符合条件的对象了。
方法二:使用Prefetch优化性能(适合大数据量)
如果你的系统数据量较大,上面的方法会为每个Pergunta触发一次额外的数据库查询,性能不够理想。这时候可以用Django的Prefetch对象,在查询Questionario时就预取过滤好的Resposta数据:
步骤1:在视图层优化查询集
from django.db.models import Prefetch from rest_framework import viewsets from .models import Questionario, Pergunta, Resposta from .serializers import QuestionarioSerializer class QuestionarioViewSet(viewsets.ReadOnlyModelViewSet): queryset = Questionario.objects.all() \ # 预取关联的Pergunta,同时预取每个Pergunta下符合条件的Resposta .prefetch_related( Prefetch( 'perguntas', # 这里要对应Questionario到Pergunta的related_name queryset=Pergunta.objects.prefetch_related( Prefetch( 'respostas', # 对应Pergunta到Resposta的related_name queryset=Resposta.objects.filter(tipo="alt"), to_attr='filtered_respostas' # 给过滤后的结果起个名字 ) ) ) ) serializer_class = QuestionarioSerializer
步骤2:修改序列化器使用预取的数据
class PerguntaSerializerModel(serializers.ModelSerializer): respostas = serializers.SerializerMethodField() class Meta: model = Pergunta fields = ('id', 'texto', 'respostas') def get_respostas(self, obj): # 直接使用预取好的filtered_respostas,避免重复查询数据库 return RespostaSerializer(obj.filtered_respostas, many=True).data
这种方法通过一次数据库查询就完成了所有过滤和预取,性能会好很多,推荐在数据量大的场景下使用。
内容的提问来源于stack exchange,提问作者Gustavo Maciel
相关产品推荐
相关产品推荐

