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

如何在Django普通模板中使用Admin内置的可排序表格系统?

嘿,这个需求我太懂了!Django Admin自带的可排序表格用起来顺手得很,但官方文档确实没明确说怎么在自定义模板里复用这套能力——不过咱们可以拆解Admin的实现逻辑,自己动手搬过来,其实没那么复杂~

核心思路拆解

Django Admin的排序本质上就是通过URL的GET参数传递排序规则,然后在后台动态调整QuerySet的排序方式,最后在模板里生成带状态的排序链接(比如当前排序的列标上箭头)。咱们只要把这个逻辑复刻到自己的视图和模板里就行。

第一步:在视图中处理排序逻辑

我习惯写一个通用的Mixin,这样所有需要排序的列表视图都能复用:

class SortableListViewMixin:
    # 默认排序字段
    default_sort_field = 'id'
    # 允许排序的字段列表,防止恶意参数
    allowed_sort_fields = []

    def get_queryset(self):
        queryset = super().get_queryset()
        # 从GET参数获取排序字段和方向
        sort_by = self.request.GET.get('sort', self.default_sort_field)
        sort_dir = self.request.GET.get('dir', 'asc')

        # 验证字段合法性,避免传入无效/恶意字段
        if sort_by not in self.allowed_sort_fields:
            sort_by = self.default_sort_field

        # 拼接排序表达式:降序就加负号
        sort_expr = f"{'-' if sort_dir == 'desc' else ''}{sort_by}"
        return queryset.order_by(sort_expr)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 把当前排序状态传到模板,用来渲染箭头和链接
        context['current_sort'] = self.request.GET.get('sort', self.default_sort_field)
        context['current_dir'] = self.request.GET.get('dir', 'asc')
        return context

然后在你的列表视图里继承这个Mixin:

from django.views.generic import ListView
from .models import Product

class ProductListView(SortableListViewMixin, ListView):
    model = Product
    template_name = 'products/list.html'
    # 允许排序的字段,包括外键关联字段(比如category__name)
    allowed_sort_fields = ['name', 'price', 'created_at', 'category__name']
    default_sort_field = 'created_at'

第二步:在模板里渲染可排序表头

直接写硬编码的链接有点麻烦,我推荐自定义一个模板标签,让代码更简洁。

首先在你的app下创建templatetags/sort_tags.py:

from django import template

register = template.Library()

@register.simple_tag(takes_context=True)
def sort_link(context, field_name, label):
    request = context['request']
    current_sort = request.GET.get('sort', '')
    current_dir = request.GET.get('dir', 'asc')

    # 复制当前的GET参数,保留其他过滤条件(比如搜索关键词)
    query_params = request.GET.copy()

    # 如果当前已经按这个字段排序,就切换方向;否则默认升序
    if current_sort == field_name:
        new_dir = 'desc' if current_dir == 'asc' else 'asc'
        query_params['dir'] = new_dir
    else:
        query_params['sort'] = field_name
        query_params['dir'] = 'asc'

    # 生成带排序参数的链接,同时标记当前排序方向
    arrow = '↑' if current_sort == field_name and current_dir == 'asc' else '↓' if current_sort == field_name else ''
    return f"<a href='?{query_params.urlencode()}'>{label} {arrow}</a>"

然后在模板里加载这个标签,就能轻松渲染表头了:

{% load sort_tags %}

<div class="table-container">
  <table class="sortable-table">
    <thead>
      <tr>
        <th>{% sort_link 'name' '商品名称' %}</th>
        <th>{% sort_link 'price' '价格' %}</th>
        <th>{% sort_link 'created_at' '上架时间' %}</th>
        <th>{% sort_link 'category__name' '分类' %}</th>
      </tr>
    </thead>
    <tbody>
      {% for product in object_list %}
        <tr>
          <td>{{ product.name }}</td>
          <td>{{ product.price }}元</td>
          <td>{{ product.created_at|date:"Y-m-d" }}</td>
          <td>{{ product.category.name }}</td>
        </tr>
      {% empty %}
        <tr>
          <td colspan="4">暂无商品</td>
        </tr>
      {% endfor %}
    </tbody>
  </table>
</div>

一些额外优化点

  • 保留其他过滤参数:上面的代码已经处理了,比如如果URL里有?search=手机,点击排序链接后会自动保留search=手机参数,不会丢失过滤状态。
  • 外键字段排序:只要把category__name这种关联字段加入allowed_sort_fields,视图的order_by就能正常处理。
  • 防止SQL注入:通过allowed_sort_fields限制可排序字段,避免用户传入恶意字段导致安全问题。
  • 样式美化:可以给当前排序的表头加个高亮样式,比如在模板里判断current_sort,给<th>加个active类。

这样一套下来,你的自定义模板里就有和Django Admin一模一样的可排序表格啦!

内容的提问来源于stack exchange,提问作者Francisco Ghelfi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:35:00