如何自定义Django Admin的list_display显示多对多关系和list_filter

在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。

如何自定义Django Admin的list_display显示多对多关系和list_filter_第1张图片

 

自定义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 = '标签'  # 设置表头

显示效果如下:如何自定义Django Admin的list_display显示多对多关系和list_filter_第2张图片

你注意到上面图片有个问题没有?当标签为空的时候,显示内容为空白。有的时候我们需要设置空白值(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)

改进的展示效果如下:

如何自定义Django Admin的list_display显示多对多关系和list_filter_第3张图片

注意:

  • 尽管我们实现了在列表中显示多对多的字段,但在实际项目中我们并不建议这么做,因为这额外地增加了许多数据库查询的工作量。

  • 获取某篇文章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', )

展示效果如下所示, 是不是很帅?

如何自定义Django Admin的list_display显示多对多关系和list_filter_第4张图片

注意:

  • 自定义的Filter类的代码必需放在ModelAdmin类的前面,否则无法使用。

  • 自定义的Filter参数名parameter_name不要使用q和next,这两个参数已作为django admin的默认参数使用了。

如何自定义Django Admin的list_display显示多对多关系和list_filter_第5张图片

你可能感兴趣的:(Django)