Django ORM: Как фильтровать отношение "многие-ко-многим" без фильтрации связанных объектов

У меня есть несколько моделей Django, таких как следующие:

class Film:
    genre = models.ManyToManyField("Genre", blank=True)

class Genre(TimeStampedModel):
    name = models.CharField(max_length=50, blank=False)
    slug = AutoSlugField(max_length=55, unique=True, populate_from="name")

Теперь я хочу выбрать все фильмы, которые связаны с жанром "Театр" и получить список всех связанных с ними жанров:

In [1]: from apps.base.models import Film, Genre

In [2]: qs = Film.objects.filter(genre__slug='theatre')

In [3]: set(qs.values_list("genre__slug", flat=True))
Out[3]: {'theatre'}

Однако это не тот результат, который я хочу получить. Если посмотреть на жанры первого фильма, возвращенного как часть набора запросов, мы можем увидеть больше жанров:

In [4]: set(qs[0].genre.all().values_list("slug", flat=True))
Out[4]: {'dance', 'education', 'theatre', 'video-recording'}

Как я могу эффективно отфильтровать фильмы до тех, которые связаны с жанром "Театр" и получить связанные с ними жанры?

Решением этой проблемы является запрос по жанру, фильтрующий по фильмам, возвращенным ранее:

In[23]: set(Genre.objects.filter(film__in=qs))
Out[23]: 
{<Genre: Dance>,
 <Genre: Education>,
 <Genre: Theatre>,
 <Genre: Video Recording>}

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

Однако такой подход кажется немного неэффективным, если используется prefetch_related('genre'), поскольку в результате один и тот же запрос будет выполняться дважды, один раз для prefetch_related('genre') и один раз для приложения, описанного выше.

Вернуться на верх