#python #django #postgresql #orm #django-orm
Вопрос:
У меня есть проект Django на EBS, и один метод, который возвращает набор Article
запросов объектов, занимает довольно много времени. Я хотел бы оптимизировать его так, чтобы это был всего один или два запроса, но я не уверен, что это вообще возможно.
Модели: WebSite
, Article
Запрос представляет собой список Articles
с разных веб-сайтов.
WebSite
модель имеет home_order
home_article_count
атрибуты a и, которые используются для выбора ряда статей и в каком порядке они расположены.
Пример для веб-сайтов 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
того , что означает статьи с веб-сайта 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 объектов веб-сайта существует 21 запрос (один, который получает веб-сайты, а другие 20 для статей).
Можно ли объединить его в один или два запроса, соблюдая WebSite.home_order
при этом и WebSite.home_article_count
?
Комментарии:
1. Это весь код для дома?
return self.get_queryset().filter(pk__in=articles_pks)
не заботится о заказе или вы просто удалили какой-то код, чтобы сделать его коротким?2. @bdbd Это весь код, спасибо за уведомление.
3. До сих пор это выглядит как старый, с которым заказ отменен
self.get_queryset().filter(pk__in=articles_pks)
. Это намеренно?4. @bdbd Нет, это не предназначено, но я могу отсортировать его в памяти, это не имеет большого значения.
Ответ №1:
Попробуйте объединить наборы запросов с помощью 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)))
В итоге у вас должно быть всего два запроса: один для получения веб-сайтов и один для создания и использования списка статей.