Menu
CoddyTech

更少的查询

本课属于 Coddy Django 学习旅程的“模型和管理后台”单元。第 19 课,共 23 课。

主页会打印每本书的作者,这需要付出代价:一个查询获取所有书籍,然后每本书的 {{ book.author.name }} 都会再运行一个查询。10 本书需要 11 个查询,1000 本书需要 1001 个查询。这就是 N+1 问题,也是 Django 页面运行缓慢的常见原因。

select_related() 可以解决这个问题:ORM 会通过 SQL JOIN 在同一个查询中获取关联的行。一个会打印每笔借阅的书名的页面需要这样写:

loans = Loan.objects.select_related("book")

把 ForeignKey 字段的名称传给它,也就是你通过 loan.book 读取的那个字段,而且它仍然可以和 filter()、order_by() 连用。它只会沿着 ForeignKey 正向关联。要获取作者的书籍或处理多对多字段,你需要使用 prefetch_related(),Authors 项目中用到了它。之后页面看起来一样,但查询次数更少。

challenge icon

挑战

中等

在 books/views.py 中,让 home 和 search 中的 QuerySet 在同一次查询中获取每本书的作者。保留搜索筛选条件。

按“运行”:页面看起来没有变化。检查会添加 10 本书,并允许每个页面执行两次查询。

亲手试试

from django.shortcuts import get_object_or_404, render

from .models import Book


def home(request):
    books = Book.objects.all()
    return render(request, "books/home.html", {"books": books})


def book_detail(request, pk):
    book = get_object_or_404(Book, pk=pk)
    return render(request, "books/book_detail.html", {"book": book})


def search(request):
    q = request.GET.get("q", "")
    books = Book.objects.filter(title__icontains=q)
    return render(request, "books/search.html", {"q": q, "books": books})
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

模型和管理后台中的所有课

自己练习: Django 在线编辑器