在Django基础(19): Django Admin管理后台详解(上)中小编我介绍了如何创建superuser,如何自定义数据表的显示选项(list_display, list_filter, list_per_page, list_editable, ordering),如何更好地显示单对多(raw_id_fields)和多对多关系(filter_horizontal),如何使用Inlines显示多张数据表在同一页面上。今天我们来看下django admin的一些高级技巧,比如如何自定义list_display和list_filter。
自定义list_display
前文中我们已经介绍过django admin的list_display选项不能用于显示多对多的字段(如tags)。如果需要通过list_display选项显示多对多的字段或模型中原本不存在的字段或方法,我们需要新增自定义的list_play方法。
我们现在ArticleAdmin里重新定义一个show_tags方法,该方法有2个变量self和obj。我们先调用obj.tags.all()获取某篇文章obj的所有tags,然后使用join方法将它们连接成字符串。由于show_tags这个名字作为表单的header读起来并不友好,我们可以通过设置该方法的short_description属性来设置表头显示为"标签".
#blog/admin.py
class ArticleAdmin(admin.ModelAdmin):
'''设置列表可显示的字段'''
list_display = ('title', 'author', 'status', 'mod_date', 'show_tags')
'''展示tags'''
def show_tags(self, obj):
tag_list = []
for tag in obj.tags.all():
tag_list.append(tag.name)
return ','.join(tag_list)
show_tags.short_description = '标签' # 设置表头
你注意到上面图片有个问题没有?当标签为空的时候,显示内容为空白。有的时候我们需要设置空白值(empty value)来更好地提示用户,有的时候我们还要以不同颜色显示提示信息。下面我们就要对admin.py做些改进,当文章没有标签时,我们以红色字体显示没有"没有标签"。在下面中我们使用了format_html方法对字符串添加了样式。
#blog/admin.py
from django.contrib import admin
from .models import Article, Category, Tag
from django.utils.html import format_html
# Register your models here.
class ArticleAdmin(admin.ModelAdmin):
'''设置列表可显示的字段'''
list_display = ('title', 'author', 'status', 'mod_date', 'show_tags')
'''展示tags'''
def show_tags(self, obj):
tag_list = []
tags = obj.tags.all()
if tags:
for tag in tags:
tag_list.append(tag.name)
return ','.join(tag_list)
else:
return format_html(
'文章{}无标签',
obj.id,)
'''设置表头'''
show_tags.short_description = '标签' # 设置表头
admin.site.register(Article, ArticleAdmin)
改进的展示效果如下:
注意:
尽管我们实现了在列表中显示多对多的字段,但在实际项目中我们并不建议这么做,因为这额外地增加了许多数据库查询的工作量。
获取某篇文章obj所对应的tags正确方法是使用obj.tags.all()而不是obj.tags.all, 否则会出现tags is not iterable的错误。你需要了解,obj.tags.all方法仅限于在模板中使用,在admin或view中使用时,千万别忘了加括号。
在本例中我们手动编写了需要显示的empty value。Django实际上是允许我们给所有的空字段设置显示名字的,我们只需要使用empty_value_display选项即可。我们还可以通过设置admin_order_field选项设置需要排序的字段。设置了admin_order_field选项的字段表头会出现一个小三角按钮,用户可以点击三角按钮实现正序或逆序排列。使用例子如下所示:
empty_value_display = "空值"
admin_order_field = ('title', 'mod_date')
自定义list_filter
自定义list_filter也是一个非常有用的Django技术,可以让用户快速找到自己需要查看或编辑的对象。在之前的案例中,我们的list_filter已经实现了按文章状态和发布时间对文章进行过滤。现在我们需要自定义一个过滤器,按文章标题所含的关键词(比如python, django)对所有文章进行过滤, 并显示在右边的过滤条件栏目里。
完整代码如下。我们定义了一个TitleKeywordFilter类,该类继承了admin的SimpleListFilter类。我们设置了过滤器的标题和参数名(keyword), 并通过lookups方法定义了过滤参数元组,并调用queryset方法返回符合查询条件的查询数据集。
from django.contrib import admin
from .models import Article, Category, Tag
class TitleKeywordFilter(admin.SimpleListFilter):
# 右侧栏人为可读的标题
title = '标题关键词'
# 在url中显示的参数名,如?keyword=xxx.
parameter_name = 'keyword'
"""
自定义需要筛选的参数元组.
"""
def lookups(self, request, model_admin):
return (
('python', '含python文章'),
('django', '含django文章'),
)
def queryset(self, request, queryset):
"""
调用self.value()获取url中的参数, 然后筛选所需的queryset.
"""
if self.value() == 'python':
return queryset.filter(title__icontains='python')
if self.value() == 'django':
return queryset.filter(title__icontains='django')
class ArticleAdmin(admin.ModelAdmin):
'''设置过滤选项'''
list_filter = ('status', TitleKeywordFilter, 'pub_date', )
展示效果如下所示, 是不是很帅?
注意:
自定义的Filter类的代码必需放在ModelAdmin类的前面,否则无法使用。
自定义的Filter参数名parameter_name不要使用q和next,这两个参数已作为django admin的默认参数使用了。