带有嵌套序列化程序的Django反向外键可提供多个结果

时间:2018-07-01 15:30:54

标签: django django-rest-framework django-orm

如何使用反向外键关系生成左外部联接查询并将其映射到嵌套序列化器?我想过滤多个外键上的结果。

models.py

class Question(models.Model):
    question_name = models.CharField(max_length=1024) 

class Paper(models.Model):    
    paper_name = models.CharField(max_length=128)

class Answer(models.Model):
    score = models.IntegerField()
    question_id = models.ForeignKey(Question, related_name='answer_questions')
    paper_id = models.ForeignKey(Paper, related_name='answer_papers')
 class Meta:
    unique_together = ("question_id", "paper_id")

serializers.py

class PaperSerializer(serializers.ModelSerializer):        
    class Meta:
        fields = ('id', 'paper_name')
        model = Paper            

class AnswerSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'score', 'question_id', 'paper_id')
        model = Answer    

class QuestionSerializer(serializers.ModelSerializer):
    answer_questions = AnswerSerializer(many=True, allow_null=True)    
    class Meta:
        fields = ('id', 'question_name', 'answer_questions')
        model = Question

views.py

class QuestionList(generics.ListAPIView):      
    def get_queryset(self):
        paper_id = self.kwargs['pk']
        queryset = Question.objects.filter(answer_questions__paper_id=paper_id, answer_questions__question_id=F('id'))
        return queryset

    serializer_class = QuestionSerializer

我的网址是     本地主机/纸/ 1 /问题/

预期输出:  (1)仅包含对应的question_id和paper_id(单个答案对象)的所有带有答案对象的问题列表。  (2)列表应包括所有问题,无论是否回答(如果未回答问题,则应返回答案对象为空的问题),即左外部联接

[
    {
        "id": 1,
        "question_id": 1,
        "answer_questions": [
            {
                "id": 24,
                "score": 5,
                "question_id": 1,
                "paper_id": 1
            },
            {
                "id": 27,
                "score": 8,
                "question_id": 1,
                "paper_id": 2
            },
            {
                "id": 28,
                "score": 6,
                "question_id": 1,
                "paper_id": 3
            }
        ]
    }
]    

当前输出: (1)对于特定的question_id ,包括所有paper_id ,我得到了多个答案对象。也就是说,对于question_id = 1和paper_id = 2,我的输出显示了带有问题对象的问题,其中question_id = 1 未在paper_id上过滤。 (2)仅回答问题(因为查询是内部联接查询)

[
    {
        "id": 1,
        "question_id": 1,
        "answer_questions": [
            {
                "id": 24,
                "score": 5,
                "question_id": 1,
                "paper_id": 1
            }
        ]
    }
]

如果这不是实现的好方法,请提出更好的优化方法。

1 个答案:

答案 0 :(得分:0)

我认为,只要稍微更改get_quesyset()方法,您就会得到期望的输出。

class QuestionList(generics.ListAPIView):
    def get_queryset(self):
        return Question.objects.all()

    serializer_class = QuestionSerializer

当您访问 QuestionList list api 时,将得到如下的输出结果

[
    {
        "id": 4,
        "question_name": "qus-1",
        "answer_questions": [
            {
                "id": 5,
                "score": 50,
                "question_id": 4,
                "paper_id": 4
            },
            {
                "id": 6,
                "score": 10,
                "question_id": 4,
                "paper_id": 5
            }
        ]
    },
    {
        "id": 5,
        "question_name": "qus-2",
        "answer_questions": []
    },
    {
        "id": 6,
        "question_name": "que-3",
        "answer_questions": [
            {
                "id": 7,
                "score": 342,
                "question_id": 6,
                "paper_id": 4
            }
        ]
    }
]

Update-1

如下更改您的序列化器

class QuestionSerializer(serializers.ModelSerializer):
    answer_questions = serializers.SerializerMethodField()

    def get_answer_questions(self, question):
        paper_id = self.context['view'].kwargs.get('paper_id')
        return AnswerSerializer(question.answer_questions.filter(paper_id=paper_id), many=True).data

    class Meta:
        fields = ('id', 'question_name', 'answer_questions')
        model = Question