Оптимизировать запросы к БД в Django - PullRequest
0 голосов
/ 30 мая 2020

У меня есть просмотр страницы в Django, настроенный следующим образом:

    blog = get_object_or_404(Blog, subdomain=extracted.subdomain)
    all_posts = Post.objects.filter(
        blog=blog, publish=True).order_by('-published_date')
    nav = all_posts.filter(is_page=True)
    posts = all_posts.filter(is_page=False)

Это вызывает доступ к базе данных 3 раза. Я пытаюсь оптимизировать это, чтобы получить доступ к БД только один раз. Следующий фрагмент сокращает количество вызовов до 2, но я уверен, что есть способ получше, о котором я не знаю.

blog = get_object_or_404(Blog, subdomain=extracted.subdomain)
all_posts = Post.objects.filter(
    blog=blog, publish=True).order_by('-published_date')
nav = []
posts = []
for post in all_posts:
    if post.is_page:
        nav.append(post)
    else:
        posts.append(post)

Насколько я понимаю, prefetch_related и select_related работают наоборот, и я не уверен, как их реализовать в этом контексте.

Мои модели настроены следующим образом:

class Blog(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
    title = models.CharField(max_length=200)
    ...

class Post(models.Model):
    blog = models.ForeignKey(
        Blog,
        on_delete=models.CASCADE,
        related_name='post')
    title = models.CharField(max_length=200)
    ...

Заранее спасибо!

Редактировать:

А для некоторых причина, по которой выполняется 3 запроса к БД

blog = get_object_or_404(Blog.objects.prefetch_related('post_set'), subdomain=extracted.subdomain)

posts = blog.post_set.filter(publish=True).order_by('-published_date')

1 Ответ

1 голос
/ 30 мая 2020

Некоторые вещи:

  • Разделение их на два набора запросов или списков - плохая идея. Используйте шаблон, чтобы проверить is_page и отобразить его только в разделе навигации или разделе сообщений.
  • Оптимизация запросов, подобных этому, - это не то место, где вы получаете большую часть производительности. Вы хотите избавиться от запросов, которые происходят при повторении набора запросов (например, в циклах for), и для этого нужны предварительная выборка и выбор.

Тем не менее, чтобы избавьтесь от лишнего запроса:

posts = Post.objects.filter(
    blog__subdomain=extracted_subdomain, publish=True
).order_by('-published_date')
if not posts:
   raise Http404('no posts for subdomain')

И чтобы убедиться, что у вас есть доступ к свойствам блога из сообщений без запроса на каждой итерации:

posts = Post.objects.filter(
    blog__subdomain=extracted_subdomain, publish=True
).select_related('blog').order_by('-published_date')
...