Django ORM комментирует запрос внешнего ключа - PullRequest
0 голосов
/ 27 мая 2019

У меня есть 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 содержит сессии, 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'))

1 Ответ

0 голосов
/ 27 мая 2019

Я не верю, что это возможно через 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 вызовет исключение. Чтобы сохранить код в чистоте, я бы, вероятно, остановился на вашем текущем подходе (но тогда - проблема остается нерешенной, чтобы держать все в одном ударе дб).

...