Требуется оптимизация запросов Django (2 запроса вместо 21)
У меня есть проект Django на EBS, и один метод, который возвращает QuerySet из Article
объектов, занимает довольно много времени. Я бы хотел оптимизировать его так, чтобы это был всего один или два запроса, но я не уверен, что это вообще возможно.
Модели: WebSite
,Article
Запрос представляет собой список Articles
с различных сайтов.
WebSite
модель имеет атрибуты home_order
и home_article_count
, которые используются для выбора количества статей и того, в каком порядке они находятся.
Пример для сайтов A, B и C:
A
-A.home_order = 2
,A.home_article_count=3
B
-B.home_order = 1
,B.home_article_count=5
C
-C.home_order = 3
,C.home_article_count=7
Результатом будет (aA означает статью с сайта A):
aB,aB,aB,aB,aB,aA,aA,aA,aC,aC,aC,aC,aC,aC,aC,aC
Списки начинаются с aB
, что означает статьи с сайта B
, потому что B.home_order=1
, есть 5 aB
статей как B.home_article_count=5
.
Сейчас это метод Manager
, который возвращает статьи:
def home(self) -> QuerySet:
articles_pks = []
for ws in WebSite.objects.active().order_by('home_order', 'name'):
articles_pks.extend(ws.articles.filter(is_active=True).order_by('-created')[:ws.home_article_count].values_list('pk',flat=True))
return self.get_queryset().filter(pk__in=articles_pks)
Значит, на 20 объектов WebSite приходится 21 запрос (один, который получает сайты, а другие 20 для статей).
Можно ли объединить его в один или два запроса, соблюдая WebSite.home_order
и WebSite.home_article_count
?
Попробуйте объединить наборы запросов с помощью оператора OR |
:
def home(self) -> QuerySet:
articles_pks = Article.objects.none()
for ws in WebSite.objects.active().order_by('home_order', 'name'):
articles_pks = articles_pks | ws.articles.filter(is_active=True).order_by('-created')[:ws.home_article_count]
return self.get_queryset().filter(pk__in=articles_pks.values_list('pk',flat=True)))
В итоге у вас должно быть всего два запроса: один для получения сайтов и один для создания и использования списка статей.