Django - 如何以有效的方式获取最新的相关模型,我可以在模板上进行迭代?

Posted

技术标签:

【中文标题】Django - 如何以有效的方式获取最新的相关模型,我可以在模板上进行迭代?【英文标题】:Django - how to obtain the latest related model in an efficent way I can iterate on the template? 【发布时间】:2021-03-14 08:52:34 【问题描述】:

假设我有两个相关模型,其中一个带有日期时间字段。 (作者和书,带有 pub_date)。

我想显示作者列表和他们每个人写的最新书籍。 我在Author模型上做了一个方法:

def get_latest_book(self):
    return self.books.all().latest('pub_date')

这是可行的,但是在模板上渲染时效率非常低:

views.py:

class AuthorListView(ListView):
    model = Author
    template_name = 'author_list.html'

    def get_queryset(self):
        return self.model.objects.filter(owner=self.request.user).order_by('name').prefetch_related('books')

author_list.html:

...
% for author in author_list %
Name: author.name - Latest publication: author.get_latest_book
% endfor %
...

这会产生大量查询,例如:

SELECT ••• FROM `app_book` WHERE `app_book`.`author_id` = 374 ORDER BY `app_book`.`pub_date` DESC LIMIT 1
  36 similar queries. 

对于我在数据库中的每个作者! 这会导致图书列表的加载时间过长。

如何以有效的方式在模板上打印作者列表及其最新书籍?

【问题讨论】:

【参考方案1】:

提高效率的一种简单方法是使用Prefetch object [Django-doc]:

from django.db.models import Prefetch

class AuthorListView(ListView):
    model = Author
    template_name = 'author_list.html'

    def get_queryset(self):
        return self.model.objects.filter(
            owner=self.request.user
        ).prefetch_related(
            Prefetch('books', Book.objects.order_by('-pub_date'), to_attr='books_ordered')
        ).order_by('name')

然后使用:

% for author in author_list %
    Name: author.name - Latest publication:  author.books_ordered.0 
% endfor %

然而,这会将所有相关书籍加载到内存中,但在单个查询中。

【讨论】:

感谢您的回答,它有效并减少了我的查询和加载时间。我唯一不清楚的是您的最后一句话:在单个查询中加载内存中的所有相关项目是一件坏事吗?为了获得最佳性能,我应该更喜欢使用什么? @Willem ,你怎么看这个:Book.objects.all().order_by('author', '-pubdate').distinct('author') 除非它不起作用如果数据库不接受不同的? @EricMartin:据我所知,Django 仅对 PostgreSQL 数据库执行此操作(这可能是唯一支持此操作的数据库),但此外它不包括 Authors还没有出版任何书。

以上是关于Django - 如何以有效的方式获取最新的相关模型,我可以在模板上进行迭代?的主要内容,如果未能解决你的问题,请参考以下文章

使用 django ORM 获取只有最新孩子的父母的优化方式

在 Django 中有效地获取相关模型的计数

Django admin自定义字段按条件获取最新相关对象的结果

快速获取最新股票相关数据,并使用数据分析进行数据清洗,获取有效信息

如何获取用户在 SQL 或 Ruby 中评论的页面上的最新评论?

如何识别 ReCaptcha V2 的 32 位数据站点密钥以使用 Selenium 和 Python 请求以编程方式获取有效响应?