Django ORM注释外键查询

时间:2019-05-27 12:33:58

标签: django django-models django-rest-framework

我有3种型号:

class Project(models.Model):
    name = models.CharField(max_length=300, unique=True)
    description = models.CharField(
        max_length=2000,
        blank=True,
        null=True,
        default=None
    )

class QuestionSession(models.Model):
    name = models.CharField(
        max_length=500, default=None, null=True, blank=True
    )
    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE,
        related_name='sessions',
        blank=True,
        null=True,
        default=None
    )

class Question(models.Model):
    description = models.CharField(max_length=500)
    question_session = models.ForeignKey(
        QuestionSession,
        on_delete=models.CASCADE,
        related_name='questions',
        blank=True,
        null=True,
        default=None
    )

如您所见,项目包含会话,会话包含问题。 我要实现的目标是获取一个包含会话和许多问题的单个项目。我可以通过2个不同的查询轻松完成此操作,但不能在1个查询中完成。

我的序列化器:

class SingleProjectSerializer(serializers.ModelSerializer):
    sessions = MinifiedSessionSerializer(many=True)

    class Meta:
        model = Project
        fields = [
            'id',
            'name',
            'description',
            'sessions'
        ]

class MinifiedSessionSerializer(serializers.ModelSerializer):
    questions_number = serializers.IntegerField()

    class Meta:
        model = QuestionSession
        fields = [
            'id',
            'name',
            'questions_number'
        ]

我曾经在单个查询中捕获会话,例如:

Project.objects.get(id=project_id).sessions.annotate(questions_number=Count('questions'))

但是现在怎么办?我需要先获取项目,然后在会话上进行注释。我不知道该怎么做。我需要这样的查询:

Project.objects.filter(pk=project_id).annotate(sessions__questions_number=Count('sessions__questions'))

1 个答案:

答案 0 :(得分:0)

我不认为通过Django ORM可以实现。我能想到的唯一解决方案是改变您要求数据的方式:

sessions = QuestionSession.objects.filter(project_id=project_id).select_related('project').annotate(questions_number=Count('questions'))
project = sessions[0].project

这将最终在单个查询中,但是我假设您想将此project实例传递给DRF序列化器。在这种情况下,project对预取的会话一无所知,因此需要单独处理。另外,当特定项目没有关联的会话时会出现问题-sessions[0].project会引发异常。为了保持代码的整洁,我可能会继续使用您当前的方法(但是,为了将所有内容都保留在一个数据库中,这个问题仍然没有解决。)