You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django函数/类视图中实现多查询集分页?

多模型搜索结果的Django分页解决方案

核心思路

Django内置的Paginator类默认针对单个QuerySet,要实现多模型分页,需先将不同模型的搜索结果合并为统一可迭代集合,再用Paginator处理分页逻辑,最后在模板中根据对象模型类型渲染对应样式。

步骤1:修改视图代码

1.1 导入依赖

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from itertools import chain
from django.db.models import Q  # 可选,用于实现标题/描述的OR匹配搜索
from django.http import HttpResponse
from django.shortcuts import render

1.2 重构视图逻辑

支持POST搜索提交与GET分页请求,合并多模型结果并处理分页:

def search_results(request):
    # 获取搜索关键词:POST提交或GET分页传递
    searched = request.GET.get('searched', '')
    if request.method == 'POST':
        searched = request.POST['searched'].strip()
        if not searched:
            return HttpResponse('Please type something in the search input.')
    
    # 无搜索词时返回空结果页面
    if not searched:
        return render(request, "search_results.html", {'searched': ''})
    
    # 多模型搜索(用Q对象实现标题/描述任意匹配,原代码为AND条件,可按需调整)
    books = Book.objects.filter(
        Q(title__icontains=searched) | Q(description__icontains=searched)
    ).order_by('-id')
    
    sermons = Sermon.objects.filter(
        Q(title__icontains=searched) | Q(description__icontains=searched)
    ).order_by('-id')
    
    other_sermons = SermonsByOtherFathers.objects.filter(
        Q(title__icontains=searched) | Q(description__icontains=searched)
    ).order_by('-id')
    
    other_books = BooksByOtherFathers.objects.filter(
        Q(title__icontains=searched) | Q(description__icontains=searched)
    ).order_by('-id')
    
    # 合并所有模型的搜索结果
    all_results = list(chain(books, sermons, other_sermons, other_books))
    
    # 可选:全局统一排序(比如按ID倒序,覆盖各模型单独排序)
    # all_results = sorted(all_results, key=lambda x: x.id, reverse=True)
    
    # 初始化分页器,每页显示10条
    paginator = Paginator(all_results, 10)
    page_num = request.GET.get('page')
    
    # 处理页码异常
    try:
        paginated_results = paginator.page(page_num)
    except PageNotAnInteger:
        paginated_results = paginator.page(1)
    except EmptyPage:
        paginated_results = paginator.page(paginator.num_pages)
    
    context = {
        'searched': searched,
        'paginated_results': paginated_results,
    }
    
    return render(request, "search_results.html", context)

步骤2:添加自定义模板标签

为在模板中识别对象所属模型,创建自定义标签:

  1. 在Django应用下新建templatetags目录(若不存在),并创建custom_tags.py文件:
from django import template

register = template.Library()

@register.filter
def model_name(obj):
    """获取对象所属模型的小写名称"""
    return obj._meta.model_name

步骤3:修改HTML模板

3.1 加载自定义标签

在模板顶部添加:

{% load custom_tags %}

3.2 渲染分页结果与导航

根据模型类型渲染不同内容,并添加分页导航:

{% for item in paginated_results %}
    {% if item|model_name == 'book' %}
        <tr>
            <td>
                <a href="{{ item.book_instance.url }}"> {{ item.title }} </a>
                <p> {{ item.author }} </p>
                <p> {{ item.category }} </p>  
                <p> {{ item.description }} </p>           
            </td>
        </tr>
    {% elif item|model_name == 'sermon' %}
        <!-- Sermon模型渲染代码 -->
        <tr>
            <td>
                <a href="{{ item.url }}"> {{ item.title }} </a>
                <p> {{ item.preacher }} </p>
                <p> {{ item.description }} </p>           
            </td>
        </tr>
    {% elif item|model_name == 'sermonsbyotherfathers' %}
        <!-- SermonsByOtherFathers模型渲染代码 -->
        <tr>
            <td>
                <a href="{{ item.url }}"> {{ item.title }} </a>
                <p> {{ item.father_name }} </p>
                <p> {{ item.description }} </p>           
            </td>
        </tr>
    {% elif item|model_name == 'booksbyotherfathers' %}
        <!-- BooksByOtherFathers模型渲染代码 -->
        <tr>
            <td>
                <a href="{{ item.book_instance.url }}"> {{ item.title }} </a>
                <p> {{ item.author }} </p>
                <p> {{ item.category }} </p>  
                <p> {{ item.description }} </p>           
            </td>
        </tr>
    {% endif %}
{% empty %}
    <tr>
        <td colspan="4">没有找到匹配的结果</td>
    </tr>
{% endfor %}

<!-- 分页导航栏 -->
<div class="pagination mt-4">
    <span class="step-links">
        {% if paginated_results.has_previous %}
            <a href="?searched={{ searched }}&page=1">&laquo; 首页</a>
            <a href="?searched={{ searched }}&page={{ paginated_results.previous_page_number }}">上一页</a>
        {% endif %}

        <span class="current mx-2">
            第 {{ paginated_results.number }} 页 / 共 {{ paginated_results.paginator.num_pages }} 页
        </span>

        {% if paginated_results.has_next %}
            <a href="?searched={{ searched }}&page={{ paginated_results.next_page_number }}">下一页</a>
            <a href="?searched={{ searched }}&page={{ paginated_results.paginator.num_pages }}">末页 &raquo;</a>
        {% endif %}
    </span>
</div>

注意事项

  • model_name返回的是小写模型类名,模板中判断条件需对应小写。
  • 分页链接必须携带searched参数,避免分页后丢失搜索条件。
  • 若模型结构兼容,可使用union方法替代chain提升合并效率,但chain更适配不同结构的模型。

内容的提问来源于stack exchange,提问作者Rawy Murgany

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:25:24