如何查询拥有至少一本关联书籍的Author对象?分页异常求助
解决Django获取拥有至少一本图书的作者查询集问题
之前你用Author.objects.all()拿全量作者,再在模板里判断是否有图书的做法,会导致两个核心问题:
- 分页逻辑混乱:分页是按全量作者数量计算的,但实际只显示有书的作者,比如每页设10个,可能实际页面只显示5个,分页导航和实际内容完全不匹配
- 性能浪费:每个作者都要额外查一次关联的图书,产生N+1查询,数据量越大性能越差
直接在数据库层面过滤出至少拥有一本图书的作者,就能彻底解决这些问题,下面是两种常用实现方式:
方法一:排除无关联图书的作者
利用Django ORM的反向关联查询,直接排除掉没有绑定Book的作者:
# 视图中获取过滤后的查询集 authors_with_books = Author.objects.exclude(book__isnull=True)
这个查询会生成对应的SQL语句,在数据库层面完成过滤,返回的结果就是所有有书的作者集合。
方法二:统计图书数量并过滤
如果后续需要显示每个作者的图书数量,可以用annotate配合Count做统计,再过滤出数量大于0的作者:
from django.db.models import Count # 同时获取作者和对应的图书数量,过滤出有书的作者 authors_with_books = Author.objects.annotate(book_count=Count('book')).filter(book_count__gt=0)
这种方式不仅能得到符合要求的作者,还能直接通过author.book_count获取该作者的图书数量,不用再额外发起查询。
结合分页使用
把过滤后的查询集传给Paginator,分页逻辑就完全正常了:
from django.core.paginator import Paginator from django.shortcuts import render def author_list(request): # 用上面任意一种方法获取过滤后的查询集 authors_queryset = Author.objects.exclude(book__isnull=True) # 每页显示10个作者 paginator = Paginator(authors_queryset, 10) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) return render(request, 'author_list.html', {'page_obj': page_obj})
模板里直接循环page_obj即可,不用再判断作者是否有书:
{% for author in page_obj %} <div class="author-item"> <h3>{{ author.name }}</h3> {# 如果用方法二,还可以直接显示图书数量 #} {# <p>图书数量:{{ author.book_count }}</p> #} </div> {% endfor %} {# 分页导航代码 #} <div class="pagination"> <span class="step-links"> {% if page_obj.has_previous %} <a href="?page=1">« 首页</a> <a href="?page={{ page_obj.previous_page_number }}">上一页</a> {% endif %} <span class="current"> 第 {{ page_obj.number }} 页 / 共 {{ page_obj.paginator.num_pages }} 页 </span> {% if page_obj.has_next %} <a href="?page={{ page_obj.next_page_number }}">下一页</a> <a href="?page={{ page_obj.paginator.num_pages }}">末页 »</a> {% endif %} </span> </div>
内容的提问来源于stack exchange,提问作者Korab Duklini
相关产品推荐
相关产品推荐

