扩展Django admin的list_filter()可使用范围方法

yipeiwu_com7年前Python基础

需求描述

有时候我们会基于已有数据生成一列在表格中,类似于下面的

class BaseSchema(models.Model):
 ...
 def test_status(self):
 # pdb.set_trace()
 if datetime.date.today() < self.test_start_date:
  return '未到测试区间'
 elif self.test_end_date and datetime.date.today() > self.test_end_date:
  return format_html('<p style="color: red">已下线</p>')
 else:
  return format_html('<p style="color: green">进行中</p>')

 test_status.short_description = u'测试状态'

但同时我们也希望可以对这一列进行筛选,按常规的话也就是添加到list_filter中:

list_filter = ('test_status')

这时候我们会看到django的温馨报错:

The value of 'list_filter[0]' refers to 'test_status', which does not refer to a Field. 

也就是说不能使用list_filter对非Field进行筛选。

解决办法

最简单的方法

那就是把这个字段记录进field啊,这样就可以用了。但是我并不想这么做

更高端的方法

参考https://stackoverflow.com/questions/12102697/creating-custom-filters-for-list-filter-in-django-admin/45136544第二个回答中的事例:

from django.contrib.admin import SimpleListFilter

class CountryFilter(SimpleListFilter):
 title = 'country' # or use _('country') for translated title
 parameter_name = 'country'

 def lookups(self, request, model_admin):
 countries = set([c.country for c in model_admin.model.objects.all()])
 return [(c.id, c.name) for c in countries] + [
  ('AFRICA', 'AFRICA - ALL')]

 def queryset(self, request, queryset):
 if self.value() == 'AFRICA':
  return queryset.filter(country__continent='Africa')
 if self.value():
  return queryset.filter(country__id__exact=self.value())

class CityAdmin(ModelAdmin):
 list_filter = (CountryFilter,)

现在我们知道django中是这样实现的筛选的方法,那我们只要覆盖这个方法就好了:

class StatusFilter(SimpleListFilter):
 title = 'status'
 parameter_name = 'status'

 def lookups(self, request, model_admin):
 return [(1, '已下线'), (2, '进行中'), (3, '未到测试区间')]

 def queryset(self, request, queryset):
 this_day = datetime.date.today()
 # pdb.set_trace()
 if self.value() == '3':
  return queryset.filter(test_start_date__gt=this_day)
 elif self.value() == '1':
  return queryset.filter(test_end_date__lt=this_day)
 elif self.value() == '2':
  return queryset.filter(test_end_date__gte=this_day, test_start_date__lte=this_day)

然后在添加进list_filter中:

list_filter = (StatusFilter,)

bingo!

以上这篇扩展Django admin的list_filter()可使用范围方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持【听图阁-专注于Python设计】。

相关文章

Python实用技巧之利用元组代替字典并为元组元素命名

前言 本文主要给大家介绍了关于Python利用元组代替字典并为元组元素命名的相关内容,下面话不多说了,来一起看看详细的介绍吧 场景: 一般使用字典定义一个人的姓名,年龄,性别,邮箱等信息...

Pyinstaller将py打包成exe的实例

Pyinstaller将py打包成exe的实例

背景:分享python编写的小脚本时,拷贝代码还缺各种环境,使用Pyinstaller将py可以打包成exe,直接运行即可 1、安装pyinstaller运行时所需要的windows拓展...

详解Django通用视图中的函数包装

用函数包装来处理复杂的数据过滤 另一个常见的需求是按URL里的关键字来过滤数据对象。 之前,我们在URLconf中硬编码了出版商的名字,但是如果我们想用一个视图就显示某个任意指定的出版商...

解决Python命令行下退格,删除,方向键乱码(亲测有效)

一、出现原因:readline模块没有安装 二、解决方式: # 安装readline模块 yum -y install readline-devel # 进入Python安装目录 c...

详解Django项目中模板标签及模板的继承与引用(网站中快速布置广告)

详解Django项目中模板标签及模板的继承与引用(网站中快速布置广告)

Django项目中模板标签及模板的继承与引用 常见模板标签 {% static %} {% for x in range(x) %}{% endfor %} 循环的序号{% forl...