如何在Django通用ListView中实现类似Admin后台的列表筛选功能?
有两种常用的简便实现方案,优先推荐使用django-filter,这是业界通用的实现方式,比照搬Admin内置的筛选逻辑简单很多。
方案1:使用django-filter实现(推荐,代码量最少)
第一步:安装配置
先安装依赖包:pip install django-filter
之后在项目settings.py的INSTALLED_APPS中添加django_filters即可。
第二步:定义筛选规则
在sales应用下新建filters.py文件,编写筛选类:
import django_filters from .models import SaleBill class SaleBillFilter(django_filters.FilterSet): # 自定义筛选规则:日期区间筛选 start_date = django_filters.DateFilter(field_name="time", lookup_expr='gte', label='起始日期') end_date = django_filters.DateFilter(field_name="time", lookup_expr='lte', label='结束日期') # 客户名模糊搜索 name = django_filters.CharFilter(lookup_expr='icontains', label='客户姓名') class Meta: model = SaleBill # 此处填写你需要的筛选字段,外键、选择型字段会自动生成下拉选择框 fields = ['billno', 'name', 'start_date', 'end_date']
第三步:修改ListView视图
from django_filters.views import FilterMixin from .filters import SaleBillFilter class SaleView(FilterMixin, ListView): model = SaleBill template_name = "sales/sales_list.html" context_object_name = "bills" ordering = ["-time"] paginate_by = 10 filterset_class = SaleBillFilter # 绑定自定义筛选类 def get_queryset(self): # 生成经过筛选的查询集 queryset = self.filterset_class(self.request.GET, queryset=super().get_queryset()).qs return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 将筛选表单传入模板用于渲染 context['filter'] = self.filterset_class(self.request.GET, queryset=self.get_queryset()) return context
第四步:修改模板
添加筛选区域
在标题下方、表格上方的位置添加筛选表单:
<div class="card mb-3"> <div class="card-body"> <form method="get" class="row g-3"> {{ filter.form.as_p }} <div class="col-auto align-self-end"> <button type="submit" class="btn btn-primary">筛选</button> <a href="{% url '你的销售列表路由名' %}" class="btn btn-outline-secondary">重置</a> </div> </form> </div> </div>
你已经加载了widget_tweaks标签,可直接用它给表单字段添加自定义样式。
修改分页链接
需要给所有分页链接带上当前筛选参数,避免切换页面时筛选失效,将所有分页的href属性修改为如下格式即可:
href="?{{ filter.form.data.urlencode }}&page=xxx"
例如第一页的链接修改为:<a class="btn btn-outline-info mb-4" href="?{{ filter.form.data.urlencode }}&page=1">First</a>
方案2:原生Django实现(无需第三方依赖)
如果不想引入额外依赖,可直接重写get_queryset方法实现筛选:
修改视图
class SaleView(ListView): model = SaleBill template_name = "sales/sales_list.html" context_object_name = "bills" ordering = ["-time"] paginate_by = 10 def get_queryset(self): queryset = super().get_queryset() # 从GET请求中获取筛选参数 name = self.request.GET.get('name') start_date = self.request.GET.get('start_date') end_date = self.request.GET.get('end_date') if name: queryset = queryset.filter(name__icontains=name) if start_date: queryset = queryset.filter(time__gte=start_date) if end_date: queryset = queryset.filter(time__lte=end_date) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 将当前筛选参数传入模板,用于表单回填 context['filter_params'] = self.request.GET return context
模板添加筛选表单
<div class="card mb-3"> <div class="card-body"> <form method="get" class="row g-3"> <div class="col-auto"> <label>客户姓名</label> <input type="text" name="name" value="{{ filter_params.name|default:'' }}" class="form-control"> </div> <div class="col-auto"> <label>起始日期</label> <input type="date" name="start_date" value="{{ filter_params.start_date|default:'' }}" class="form-control"> </div> <div class="col-auto"> <label>结束日期</label> <input type="date" name="end_date" value="{{ filter_params.end_date|default:'' }}" class="form-control"> </div> <div class="col-auto align-self-end"> <button type="submit" class="btn btn-primary">筛选</button> <a href="{% url '你的销售列表路由名' %}" class="btn btn-outline-secondary">重置</a> </div> </form> </div> </div>
分页链接同样需要带上筛选参数,格式为:href="?{{ filter_params.urlencode }}&page=xxx"
内容的提问来源于stack exchange,提问作者E_K
相关产品推荐
相关产品推荐

