Вложенный фильтр Django prefetch_related

Получили классы Student, StudentGroup, Pair(double lesson), Mark и набор queryset:

class Student(models.Model):
    student_group = models.ForeignKey("StudentGroup", ...)
    ...


class StudentGroup(models.Model):
    ...

class Pair(models.Model):
    pair_time = models.TimeField(...)
    pair_date = models.DateField(...)
    student_group = models.ForeignKey("StudentGroup", ...)
    ...

class Mark(models.Model):
    student = models.ForeignKey("Student", ...)
    pair = models.ForeignKey("Pair", ...)

queryset = (
        Student.objects
        .select_related("student_group")
        .prefetch_related(
            Prefetch(
                "student_group__pairs",
                queryset=(
                    Pair.objects
                    .order_by("-pair_date", "pair_time")
                    .select_related("subject")
                    .prefetch_related(
                        Prefetch(
                            "marks",
                            # This is what I need to filter.
                            queryset=Mark.objects.filter(student_id=**???**),
                            to_attr="student_marks"
                        )
                    )
                    .all()
                ),
                to_attr="student_pairs"
            )
        )
        .all()
    )

Мне нужно отфильтровать оценки по идентификатору студента, паре привязок и оценкам (а не просто получить оценки студента). Как я могу это сделать? Пробовал F, Q, Subquery, но не могу понять, как их использовать.

Если только для фильтрации оценок по каждому ученику, то добавьте related_name к student на Mark модель:

class Mark(models.Model):
    student = models.ForeignKey(
        "Student", 
        on_delete=models.CASCADE, 
        related_name="marks"
    )
    grade = models.CharField(max_length=2)
    ...

И используйте это обратное отношение для запроса и агрегирования оценок по Student:

qs = (
    Student.objects.all()
    .prefetch_related("marks")
    .annotate(g_marks=F("marks__grade"))
)
Вернуться на верх