在嵌套序列化程序上进行过滤-Django REST

我有以下models.py

class Question(models.Model):

    code = models.CharField(max_length=12)
    text = models.CharField(max_length=1000,null=True)
    catgeroy = models.ForeignKey(
        Category,on_delete=models.PROTECT,null=True,blank=True,db_index=True,related_name='category')


class Answer(models.Model):

    question = models.ForeignKey(
        Question,related_name='question')
    exam = models.ForeignKey(Exam,on_delete=models.CASCADE)
    value = models.FloatField(null=True,blank=True)


class Exam(models.Model):

    year = models.IntegerField()

我嵌套的serializer看起来像这样:


class AnswerSerializer(serializers.ModelSerializer):

    related_name = 'answer'

    class Meta:
        model = Value
        fields = ('id','value','question','exam')


class nestedQuestionAnswerSerializer(serializers.ModelSerializer):

    answer = AnswerSerializer(many=True,read_only=True)

    class Meta:
        model = Question
        fields = (
            'id','code','text','answer'
        )

我的views.py看起来像这样:

class QuestionAnswerViewSet(BaseCertViewSet):
    queryset = Question.objects.all()
    serializer_class = serializers.nestedQuestionAnswerSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_fields = ('category',)

我的urls.py看起来像这样:

router.register('question-answer',views.QuestionAnswerViewSet,'question-answer')

我想做的是同时按类别和考试进行过滤(这是一个子属性)。所以像这样:https://example.com/api/question-answer?category=4&exam=21

这可能应该返回所有属于category = 4并出现在exam = 21上的问题。

我单独使用category进行过滤没有问题,但是似乎无法对作为子外键的exam进行过滤。

我已经尝试了许多关于SO的解决方案,但似乎没有一个能解决上述问题。

更新:

感谢大家提出的建议解决方案。

我最终使用了this solution

添加了列表序列化器类并修改了to_representation函数:

class FilteredAnswerSerializer(serializers.ListSerializer):
    def to_representation(self,data):
        qry_exam = self.context['request'].GET.get('exam')
        data = data.filter(exam=qry_exam)
        return super(FilteredAnswerSerializer,self).to_representation(data)

,然后在我的Answer序列化程序中将其命名为:


class AnswerSerializer(serializers.ModelSerializer):

    related_name = 'answer'

    class Meta:
        model = Value

        list_serializer_class = FilteredAnswerSerializer

        fields = ('id','exam')
huakaijianyueming 回答:在嵌套序列化程序上进行过滤-Django REST

一种方法是create a custom FilterSet for the ViewSet using django-filter

这是更易读,更可取的方式,因为将来代码会更清晰,更容易更改。

实现这一目标的一种非常简单,扩展性较差的方法是访问override the get_queryset method of the ViewSet class

from django.db.models import Prefetch

class NestedQuestionAnswerSerializer(serializers.ModelSerializer):
    answer = AnswerSerializer(source="filtered_answers",many=True,read_only=True)

    class Meta:
        model = Question
        fields = ('id','code','text','answer')

class QuestionAnswerViewSet(BaseCertViewSet):
    queryset = Question.objects.all()
    serializer_class = serializers.NestedQuestionAnswerSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_fields = ('category',)

    def get_exam_param(self):
        """ A helper to extract the exam id from the query_params. """
        try:
            return int(self.request.query_params["exam"])
        except (KeyError,ValueError,TypeError):
            return None

    def get_queryset(self):
        queryset = super().get_queryset()
        exam = self.get_exam_param()
        if exam is not None:
            queryset = queryset.filter(answer__exam_id=exam).prefetch_related(
                Prefetch(
                    "answers",queryset=Answer.objects.filter(exam_id=exam),to_attr="filtered_answers",),)
        else:
            queryset = queryset.prefetch_related(
                Prefetch(
                    "answers",queryset=Answer.objects.all(),)
        return queryset

编辑 :在filtered_answers和{ 通过评论更新了对问题的理解。大部分改编自this answer here

,

您可以创建过滤器类,在该过滤器类中,您可以写下自定义字段及其查询。

from django_filters import rest_framework as filters
class QuestionFilter(filters.FilterSet):
   exam = filters.IntegerField(method="filter_exam")

  class Meta:
       fields = ('category','exam')

  def filter_exam(self,queryset,name,value):
     return queryset.filter(answer__exam_id=value)

可见

class QuestionAnswerViewSet(BaseCertViewSet):
    queryset = Question.objects.all()
    serializer_class = serializers.NestedQuestionAnswerSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filter_class = QuestionFilter
,

感谢大家提出的建议解决方案。

我最终使用了this solution

添加了列表序列化器类并修改了to_representation函数:

class FilteredAnswerSerializer(serializers.ListSerializer):
    def to_representation(self,data):
        qry_exam = self.context['request'].GET.get('exam')
        data = data.filter(exam=qry_exam)
        return super(FilteredAnswerSerializer,self).to_representation(data)

,然后在我的Answer序列化程序中将其命名为:


class AnswerSerializer(serializers.ModelSerializer):

    related_name = 'answer'

    class Meta:
        model = Value

        list_serializer_class = FilteredAnswerSerializer

        fields = ('id','value','question','exam')

我将用解决方案更新我的问题。

本文链接:https://www.f2er.com/3033024.html

大家都在问