Поиск аннотированного списка братьев и сестер в Django

У меня есть простая база данных с двумя моделями, которые определяют отношения родитель-ребенок. В ней ребенок может иметь два возможных пола, "Мужской" или "Женский".

class Parent(models.Model):
    id = models.UUIDField(primary_key=True, editable=False, unique=True, )
    name =  models.CharField(max_length=64)


MALE = "MALE"
FEMALE = "FEMALE"

class Child(models.Model):
    id = models.UUIDField(primary_key=True, editable=False, unique=True, )
    name =  models.CharField(max_length=64)

    parent = models.ForeignKey(
        Parent,
        null=True,
        on_delete=models.SET_NULL)

    GENDER = [
        (MALE, 'Male'),
        (FEMALE, 'Female'),
    ]
    status = models.CharField(
        max_length=8,
        choices=GENDER
    )

Для целей данного вопроса родитель будет иметь только ноль или один ребенок мужского пола и ноль или один ребенок женского пола. (Хотя это и не закреплено в определении модели базы данных)

Я хотел бы получить аннотированный запрос, который возвращает все Parent объекты, аннотированные с их дочерними мужскими и женскими детьми. Я не могу понять, как это сделать: Я могу получить список всех родителей, всех детей мужского пола и всех детей женского пола, но я не знаю, как собрать их вместе, чтобы нужные дети были с нужным родителем.

Это далеко, как я понял:

annotated_parent_set = Parent.objects.get_queryset()
brothers = Child.objects.filter(gender=MALE)
sisters = Child.objects.filter(gender=FEMALE)
annotated_parent_set = annotated_parent_set.annotate(
    brother=F(???))
)
annotated_parent_set = annotated_parent_set.annotate(
     sister=F(???))
)

Как мне теперь объединить их, чтобы получить нужную мне аннотацию?

Вам не нужно аннотировать это, вы можете .prefetch_related(…) [Django-doc] это с:

annotated_parent_set = Parent.objects.prefetch_related('child_set')

или если вы хотите использовать .brothers.all() и .sisters.all(), то вы можете работать с двумя Prefetch объектами [Django-doc]:

from django.db.models import Prefetch


annotated_parent_set = Parent.objects.prefetch_related(
    Prefetch('child_set', Child.objects.filter(status=MALE), to_attr='brothers'),
    Prefetch('child_set', Child.objects.filter(status=FEMALE), to_attr='sisters')
)
Вернуться на верх