【问题标题】:Django ORM annotate on foreign key queryDjango ORM注释外键查询
【发布时间】:2019-10-13 00:53:07
【问题描述】:

我有 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
    )

如您所见,Project 包含 Sessions,Session 包含问题。 我想要实现的是我想获取一个包含会话和问题数量的项目。我可以用 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'))

【问题讨论】:

  • prefetch_related() 是你的朋友。它将执行一个额外的查询来获取所有会话,您可以向它提供一个查询集,其中包含带有注释的问题数的会话。

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


【解决方案1】:

我不相信通过 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 会引发异常。为了保持代码干净,我可能会继续使用您当前的方法(但是 - 问题仍未解决,无法将所有内容保存在一个数据库中)。

【讨论】:

    猜你喜欢
    • 2020-01-26
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 2016-12-25
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    相关资源
    最近更新 更多