带有嵌套序列化程序的 Django 反向外键给出了多个结果

Posted

技术标签:

【中文标题】带有嵌套序列化程序的 Django 反向外键给出了多个结果【英文标题】:Django Reverse Foreign key with nested serializer gives multiple results 【发布时间】:2018-12-10 00:01:32 【问题描述】:

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

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】:

我认为,如果您稍微更改 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
            
        ]
    
]

更新-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

【讨论】:

感谢您的回复。但是对于论文中的每个问题,我只想在同一篇论文中回答该问题的对象。 (paper_id 可以从 URL 中获取) 更新了答案 (Update-1)。调整您的 urls 以便它可以传递给 view 结果仅给出已回答的问题。我想要所有的问题,不管他们是否得到回答。 (如果没有回答问题,则应返回答案对象为空的问题)即左外连接 我确实得到了想要的输出Refer this screenshot,这是错的吗? 对不起,这是我的错误。我在视图中对 Question 对象应用了过滤器。非常感谢您的帮助。

以上是关于带有嵌套序列化程序的 Django 反向外键给出了多个结果的主要内容,如果未能解决你的问题,请参考以下文章

Django 深度序列化 - 遵循反向外键约束

Django rest框架嵌套序列化程序创建方法

带有查找字段的嵌套模型外键上的 Django JOIN

Django 多注解返回错误结果

在模板中将外键反向到 django-fts 可搜索模型

DRF:使用嵌套序列化程序的简单外键分配?