Django入门教程

前言

第一章: django快速入门

第二章: django MTV架构

第三章: django视图

第四章: django模板

第五章: django模型

第六章: django后台管理系统

第七章: 项目实战-简易的博客系统

第八章:django表单

第九章:django用户认证系统

第十章:django中的会话

第十一章:django安全

第十二章:django性能优化

第十三章:django实用工具

首页 > Django入门教程 > 第六章: django后台管理系统 > 6.3节: 自定义模型列表页

6.3节: 自定义模型列表页

薯条老师 2020-08-27 07:16:05 295389 0

编辑 收藏

广州番禺Python, Java小班周末班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人,学员的平均就业薪资有11K不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。培训的课程有Python爬虫,Python后端开发,Python办公自动化,Python大数据分析,Python量化投资,Python机器学习,Java中高级后端开发。授课详情请点击:http://chipscoco.com/?cate=6

6.3.1 ModelAdmin类型

ModelAdmin类型中提供了许多选项和方法,通过覆盖这些选项和方法可以灵活地对模型的列表页和编辑页进行自定义。对列表页或编辑页进行自定义,需要从ModelAdmin中派生一个子类,然后在子类中覆盖这些选项和方法。在本节的内容中,以Blog模型来进行演示:

class Blog(models.Model):
    author = models.CharField(max_length=20, verbose_name="作者")
    title = models.CharField(max_length=50, verbose_name = "标题")
    content = models.TextField(verbose_name="内容")
    pub_time = models.DateTimeField(auto_now_add=True, verbose_name="发布时间")
    modify_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")
    categories = [(0, "python"), (1, "C"), (2, "C++"),]
    category = models.IntegerField(choices = categories, default=0, verbose_name="内容分类")
    illustration = models.ImageField(upload_to='images', null=True,verbose_name="插图")

def __str__():
    return self.title

进入后台首页以后,点击页面的Blogs链接:

image.png 

可进入模型的列表页:

image.png 

列表页中显示的标题,为在模型中的__str__方法返回的博客标题。在admin.py中定义ModelAdmin的子类型BlogAdmin:

# 定义ModelAdmin的子类型
class BlogAdmin(admin.ModelAdmin):
    pass

6.3.2 list_display选项

通过list_display选项,可以控制模型中的哪些字段可以显示在后台中的列表页。list_display支持以下三种类型:

(1) 模型字段名

在list_display中直接添加模型的字段名,字段名会显示在列表页中,未添加的模型字段不会进行显示。

代码实例:

from django.contrib import admin
from .models import Blog
class BlogAdmin(admin.ModelAdmin):
    list_display = ("id","author","title")

页面效果:

 image.png

(2) 可调用对象

在list_display中传递可调用对象时,django会自动将模型对象作为参数传递值可调用对象。在可调用对象中可以自定义模型字段的显示名称。

代码实例:

from django.contrib import admin
from .models import Blog
 
# 定义一个可调用对象,函数即为一种可调用对象
# django会自动将模型对象作为参数进行传递
def custom_content(obj):
    return obj.content[:20]+'...'
 
# 通过可调用对象的short_description属性来定义一个简短的显示名称
custom_content.short_description = '内容'
 
 
class BlogAdmin(admin.ModelAdmin):
    list_display = ("id","author","title",custom_content)

页面效果:

image.png 

(3) 字符串对象

这里的字符串对象指的是在ModelAdmin子类或模型中定义的方法名。在ModelAdmin子类中定义custom_content方法:

from django.contrib import admin
 
from .models import Blog
 
class BlogAdmin(admin.ModelAdmin):
    # django会自动将模型对象作为参数进行传递
    def custom_content(obj):
        return obj.content[:20]+'...'
 
    # 通过函数对象的short_description属性来定义一个简短的显示名称
    custom_content.short_description = '内容'
    list_display = ("id","author","title","custom_content")
 


在Blog模型中定义custom_content方法:
class Blog(models.Model):
    author = models.CharField(max_length=20, verbose_name="作者")
    title = models.CharField(max_length=50, verbose_name = "标题")
    content = models.TextField(verbose_name="内容")
    
    # 在模型中定义一个custom_content方法
    def custom_content(self):
        return self.content[:20]+'...'
        # 定义custom_content函数的简短名称
    custom_content.short_description = '内容'
 
 

# admin.py中的代码:
from django.contrib import admin
from .models import Blog
class BlogAdmin(admin.ModelAdmin):
    list_display = ("id","author","title","custom_content")

页面效果:

 image.png

使用list_display选项的注意事项:

1. 模型字段如果是外键类型,则显示的为__str__方法返回的名称。

2. 不支持对ManyToManyField字段进行自定义

3. 模型字段如果是BooleanField类型,则在后台中显示的是 “打开”或者“关闭” 的图标,而非True或者False。

4. 如果在list_display选项中传递的为可调用对象,django会将输出中的html标签进行转义,避免自动转义,可使用format_html方法。

6.3.3 list_display_links选项

list_display_links选项用来为列表页中的字段定义超链接,点击该超链接可以跳转到模型的修改页。在后台管理系统中,默认只对模型的主键字段显示超链接。

代码实例:

from django.contrib import admin
from .models import Blog
def custom_content(obj):
    return obj.content[:20]+'...'
 
custom_content.short_description = '内容'
 
class BlogAdmin(admin.ModelAdmin):
    list_display = ("id","author","title",custom_content)
    list_display_links = ("id","author","title")

页面效果:

image.png 

现在通过点击作者或标题的内容,也可以跳转到模型数据的编辑页。

6.3.4 list_filter选项

list_filter翻译过来即为列表过滤,顾名思义,用来对数据进行筛选。list_filter支持过滤的类型有: BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey或ManyToManyField。在ModelAdmin子类中定义list_filter选项以后,在列表页的右侧会出现一个用来过滤的工具栏。

代码实例

from django.contrib import admin
 
from .models import Blog
 
def custom_content(obj):
    return obj.content[:20]+'...'
 
custom_content.short_description = '内容'
 
class BlogAdmin(admin.ModelAdmin):
    list_display = ("id","author","title",custom_content)
    list_display_links = ("id","author","title")
    # 根据作者和博客的修改时间进行筛选
    list_filter = ("author", "modify_time")

页面效果:

image.png 

页面右侧多了一个用来进行数据筛选的工具栏。list_filter选项也支持自定义数据列的筛选行为,需要从django.contrib.admin.SimpleListFilter类中进行继承,然后覆盖类中的title和parameter_name属性,以及lookups和queryset方法。

(1) title用来定义一个人类可读的名称,会显示在工具栏。

(2) parameter_name用来定义查询URL中的参数。

(3) lookups方法返回一个二维元组,元组中的第一个元素用来进行筛选,会出现在查询URL里面。元组中的第二个元素用来定义一个人类可读的名称,会显示在右侧的工具栏。二维元组的格式:(('coded_value', 'human_readable_name'),)coded_value表示筛选的选项,human_readable_name表示该选项对应的人类可读名称。

(4) queryset方法返回一个数据筛选过后的QuerySet对象。

queryset方法:

queryset(self, request, queryset)

通过self.value可以获取查询URL中的参数值,request是一个HttpRequest对象,queryset是模型对应的QuerySet对象。现在自定义数据列的筛选行为,根据博客的修改时间来进行筛选:

from django.contrib import admin
 
import datetime
from .models import Blog
 
def custom_content(obj):
    return obj.content[:20]+'...'
 
custom_content.short_description = '内容'
 
 
class ModifyTimeListFilter(admin.SimpleListFilter):
    title = '博客修改时间进行筛选'
    parameter_name = 'latest'
    def lookups(self, request, model_admin):
        return (('3',  '最近3天'),)
        
    def queryset(self, request, queryset):
        cur_date = datetime.datetime.now().date()
        try:
            days = int(self.value())
            latest_date = cur_date - datetime.timedelta(days=days)
        except:
            latest_date = None
            if latest_date:
                return queryset.filter(modify_time__gte=latest_date)
            else:
                return queryset.filter()
 
class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author", "title")
    list_filter = ("author",ModifyTimeListFilter,)

页面效果:

image.png 

点击工具栏下方的最近3天链接时,页面的url为:http://127.0.0.1:8080/admin/chipscoco/blog/?latest=3

查询URL中的latest即为SimpleListFilter中的parameter_name,查询URL中的参数值可以通过SimpleListFilter对象的value方法进行获取,如此可根据不同的参数值来进行数据筛选。

6.3.5 list_per_page选项

设置list_per_page选项用来控制列表页每页显示的数据条数,列表页默认每页显示100条。

代码实例:

class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author", "title")
    list_filter = ("author",ModifyTimeListFilter,)
    list_per_page = 1

页面效果:

image.png 

6.3.6 date_hierarchy选项

使用date_hierarchy来根据日期字段类型进行分层筛选。

代码实例

class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author", "title")
    list_filter = ("author",ModifyTimeListFilter,)
    # 根据修改时间来进行分层筛选
    date_hierarchy = "modify_time"

页面效果:

image.png 

6.3.7 search_fields选项

使用search_fields选项来进行文本搜索,django会在列表页上方添加一个搜索框。在search_fields选项中传递模型的字段名,传递多个字段时,表示的是逻辑或关系。

代码实例:

class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author", "title")
    list_filter = ("author",ModifyTimeListFilter,)
    date_hierarchy = "modify_time"
    # 根据博客的标题或内容进行模糊搜索
    search_fields = ["title","content"]

页面效果:

image.png 

search_fields还支持对ForeignKey或ManyToManyField字段进行相关查询。查询的语法格式:

search_fields = ['foreign_key__related_fieldname']

foreign_key表示模型中的外键字段,related_fieldname表示主表中的字段名,在进行搜索时会根据主表字段的值来搜索当前模型中的外键字段。

例如Blog模型与User模型为主从关系,Blog模型中定义了author字段,表示User模型的外键,User模型中包含一个email字段,表示用户的邮件地址。当定义如下的搜索选项时:search_fields = ['author__email'], django会根据邮件地址来搜索当前模型中的author。search_fields同时还支持字段查询:search_fields = ['author__exact'],表示对author值进行精确匹配。

6.3.8 list_editable选项

使用list_editable选项可以直接在列表页对字段值进行修改,要注意的是,list_editable中的字段名必须出现在list_display选项中,且不能存在于list_display_links选项中。

代码实例:

class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author")
    list_filter = ("author",ModifyTimeListFilter,)
    date_hierarchy = "modify_time"
    # 根据博客的标题或内容进行模糊搜索
    search_fields = ["title","content"]
    list_editable = ["title"]

页面效果:

image.png 

6.3.9 get_queryset方法

列表页默认会展示所有对象,通过重写get_queryset方法,可以对数据的展示进行控制。例如在博客系统中,当用户为管理员时就展示所有文章,如果是普通用户,则仅展示当前用户所发表的文章。

方法的参数

描述

request

HttpRequest对象,可以基于HttpRequest对象的属性值来进行逻辑控制。


方法的返回值

描述

QuerySet对象

用来对模型数据进行筛选的QuerySet对象

代码实例:

class BlogAdmin(admin.ModelAdmin): 
    list_display = ("id","author","title","modify_time",custom_content)
    list_display_links = ("id", "author")
    list_filter = ("author",ModifyTimeListFilter,)
    date_hierarchy = "modify_time"
    
    # 根据博客的标题或内容进行模糊搜索
    search_fields = ["title","content"]
    list_editable = ["title"]
    
    # 用户为管理员时展示所有文章
    # 如果为普通用户,则仅展示当前用户所发表的文章
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)

6.3.10 get_search_result方法

使用get_search_result方法来对列表页的搜索结果进行修改。

参数名

描述

request

HttpRequest对象,可以基于HttpRequest对象的属性值来进行逻辑控制。

queryset

QuerySet对象

search_term

用户在搜索框中输入的查询项

 

方法的返回值

描述

result

一个元组对象,格式为:(QuerySet,use_distinct),元组中的第一个元素是一个对模型数据进行筛选的QuerySet对象,第二个元素是一个布尔类型,表示是否包含重复的数据

代码实例:

class BlogAdmin(admin.ModelAdmin): 
    # 在列表页中显示博客的分类category
    list_display = ("id","author","title","modify_time","category",custom_content)
    list_display_links = ("id", "author")
    list_filter = ("author",ModifyTimeListFilter,)
    date_hierarchy = "modify_time"
    
    # 根据博客的标题或内容进行模糊搜索
    search_fields = ["title","content"]
    list_editable = ["title"]
    
    def get_search_results(self, request, queryset, search_term):
        # 先执行父类的get_search_results方法,获取查询结果
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
        try:
            search_term_as_int = int(search_term)
        except ValueError:
            pass
        else:
            # 如果查询项为整型,则再根据category值进行筛选
            queryset |= self.model.objects.filter(category=search_term_as_int)
        return queryset, use_distinct

页面效果:

image.png 

0对应的分类是python, 在搜索框中输入0时,搜索出来的结果的内容分类为python。

6.3.11 最具实力的小班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。打算参加小班培训的同学,必须遵守薯条老师的学习安排,认真做作业和项目。把知识学好,学扎实,那么找到一份高薪的工作就是很简单的一件事。

(1) Python后端工程师高薪就业班,月薪11K-18K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,包拿Offer
(3) 数据分析高薪就业班,月薪11K-15K, 免费领取课程大纲
(4)
Python大数据挖掘,量化投资就业班,月薪12K-25K,免费领取课程大纲

扫码免费领取Python学习资料:



欢迎 发表评论: