Django агрегация для 3 связанных таблиц с отношением один к одному и один ко многим
У меня есть 3 модели django (таблицы), допустим, певец, альбом и песня.
singer имеет колонки id, album_id (внешний ключ к таблице album), first_name, last_name
album имеет колонки id, title, num_of_album_wishlist, num_of_album_stars
song имеет колонки id, album (внешний ключ к таблице album) num_of_streams, song_duration_in_secs
Певец имеет отношение один к одному с альбомом, а альбом имеет отношение один ко многим с песней.
эти таблицы являются лишь фиктивным представлением и не обязательно имеют смысл, но адекватно демонстрируют проблему.
Нужно создать кверисет, в котором для каждого певца (в кверисете), нужно узнать сумму num_of_album_wishlist, num_of_album_stars из таблицы song, а также total_num_of_songs для пользователя, sum of num_of_streams и song_duration_in_secs в одном кверисете.
Singer.objects.annotate(
wishlist=Sum('album__num_of_album_wishlist'),
stars=Sum('album__num_of_album_stars'),
streams=Sum('album__song_group__num_of_streams'),
duration=Sum('album__song_group__song_duration_in_secs')
)
Приведенный выше запрос дает неверные результаты, связанные с отношением один ко многим между таблицей альбомов и таблицей песен.
subq = Singer.objects.annotate(
streams=Sum('album__song_group__song_duration_in_secs'),
duration=Sum('album__song_group__song_duration_in_secs')
).filter(pk=OuterRef('pk'))
queryset = Singer.objects.prefetch_related(
'album').annotate(
streams=Subquery(subq.values('streams')),
duration=Subquery(subq.values('duration')),
wishlist=Sum('album__num_of_album_wishlist'),
stars=Sum('album__num_of_album_stars'),
)
Использование подзапроса для решения этой проблемы работает, но создает различные блоки для объединения в SQL-запросе (что в дальнейшем приводит к длительному времени выполнения запроса)
Есть предложения, как решить эту проблему?
Вы можете попробовать выполнить предварительную выборку album__song_group в подзапросе. Это должно стать быстрее.