本文首发于公众号:Hunter后端
这一篇介绍一下 Django 的后台界面使用。
Django 自带了一套后台管理界面,可用于我们直接操作数据库数据,本篇笔记目录如下:
- 创建后台账号以及登录操作
- 注册后台显示的数据表
- 列表字段的显示操作
- 字段值的修改操作
- 列表页的执行操作
1、创建后台账号以及登录操作
首先我们需要创建一个可以访问后台的账号,以下命令在系统的根目录下进行:
python3 manage.py createsuperuser
然后他会提示我们输入账号的名称,邮箱以及两遍密码用于确认。
Username (leave blank to use 'hunter'): admin
Email address: [email protected]
Password:
Password (again):
在这个过程中,如果我们输入的密码少于8位或者过于简单,他会给我们提示说密码过于简单等,可以设置复杂点的,也可以直接确认。
创建好账号密码后,运行我们的系统:
python3 manage.py runserver 0:9898
然后就可以在浏览器里访问我们的后台系统了:
http://localhost:9898/admin
在下面的图里输入账号密码就可以进入系统了:
这里需要注意一点的是,如果你是按照我们的笔记一路操作过来,在前面我们的用户登录限制里可能限制了 login 和 register 接口才允许不登录,那么我们在相应的验证中间件里可以简单做一下操作:
class AuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
path = request.path
# url 路径为 /users/register 和 /users/login 的接口不需要进行判断验证
if path not in [
"/users/register",
"/users/login",
]:
if path.startswith("/admin"):
return self.get_response(request)
session = request.session
if not session.get("username"):
return JsonResponse({"code": -1, "msg": "not login"}, status=401)
response = self.get_response(request)
return response
这里我们将 /admin 开头的接口都设置为了不需要登录验证。
2、注册后台显示的数据表
输入账号密码登录后台系统后,如果之前没有做过后台注册的相关操作的话,可能只会看到 Django 系统自带的 Users 和 Groups 表,它们是默认在后台显示的。
如果你点击进入 Users 表,可以看到我们刚刚创建的这个用于登录的管理员账号 admin。
如果我们想要使得我们创建的其他表也在后台显示,则需要手动去注册一下。
注册的流程很简单,我们这里以 blog 这个 application 为例,修改 blog/admin.py,对于需要显示的表,我们直接使用 admin.site.register() 操作,即可在后台显示,比如:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
admin.site.register(Blog)
重启系统后,就可以看到多了一个 Blog 的 application 以及其下的 Blog 表了。
再点击进入表,可以看到一条条 Blog 表里的数据了,但是表的字段在列表页都是被隐藏的,只有在点击进入单条数据详情页时,才会显示具体的字段值。
3、列表字段的显示操作
前面介绍了如何注册一个 model,使其在后台界面显示,但是有一个问题就是数据列表每条都只有一个字段表示,而没有每个字段的具体值显示,接下来我们就对具体字段值的显示做介绍。
首先,我们使用的 model 定义如下:
class Blog(models.Model):
PUBLISHED = 1
UNPUBLISHED = 0
PUBLISHED_STATUS = (
(PUBLISHED, "published"),
(UNPUBLISHED, "not_published"),
)
name = models.CharField(max_length=100, unique=True)
tag_line = models.TextField()
char_count = models.IntegerField(verbose_name="文章字数", default=0)
is_published = models.BooleanField(choices=PUBLISHED_STATUS, default=UNPUBLISHED)
pub_datetime = models.DateTimeField(verbose_name="发布日期", null=True, default=None)
定义好后的 migration 相关操作可以自己去完成。
注册操作
前面介绍了 model 在后台显示的注册操作:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
admin.site.register(Blog)
但是这种操作只能在后台显示列表信息,具体的字段信息不会在列表显示,如果要实现这种操作,我们需要进行另一种注册方式:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
class BlogAdmin(admin.ModelAdmin):
pass
admin.site.register(Blog, BlogAdmin)
接下来,我们的具体操作都会在 BlogAdmin 中实现。
列表显示字段
如果我们想要在列表中就显示数据的具体字段,比如 id, name,is_published,pub_datetime 三个字段,我们可以使用 list_display 属性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "pub_datetime")
重启系统后,就可以在列表看到相应的字段显示了:
注意:在这里,is_published 这里直接显示了该字段的用于显示的值,这个和之前介绍的 get_field_display() 的方式是一致的。
可以看到,这个列表的表头就是我们定义的 model 里的 verbose_name 的值,如果没有定义该属性,则会直接显示字段名。
数据格式化显示
可以注意到日期的显示并不利于直观的查看,所以可以对日期字段做一个格式化处理返回显示。
以下是对 model 的处理:
# blog/models.py
from django.contrib import admin
class Blog(models.Model):
# 字段在这里省略
pass
@admin.display(description="发布时间")
def format_pub_datetime(self):
return self.pub_datetime.strftime("%Y-%m-%d %H:%M:%S")
以下是对 BlogAdmin 的处理:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
这样在列表页就会多一列,表头为【发布时间】。
这里我们其实可以这样理解,我们对 Blog 这个 model 添加了一个名为 format_pub_datetime 的属性,这个属性用 admin.display() 作为装饰器,这个属性可以作为被 admin 的 list_display 使用作为列表的展示项。
在这里我们是直接对 pub_datetime 字段做格式化处理,当然也可以对非时间字段做其他的处理,主要看想要实现的效果。
注意: 这里还有需要注意的一点是,pub_datetime 字段是允许为 null 的,所以这里最好是做一下适配处理,比如说 return 的时候判断一下:
@admin.display(description="发布时间")
def format_pub_datetime(self):
return self.pub_datetime.strftime("%Y-%m-%d %H:%M:%S") if self.pub_datetime else ""
上面这种方式是在 model 下定义的函数,我们也可以直接在 BlogAdmin 定义该函数操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
@admin.display(description="发布时间")
def format_pub_datetime(self, obj):
return obj.pub_datetime.strftime("%Y-%m-%d %H:%M:%S") if obj.pub_datetime else ""
列表数据排序
列表的数据默认是按照 id 的倒序排列返回的,如果想要按照其他字段排序返回,比如 char_count,可以使用 ordering 属性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
ordering = ("char_count",)
如果是想要倒序排列,字段前加一个 - 即可:
ordering = ("-char_count",)
4、字段值的修改操作
如果我们想要在 admin 的页面修改数据的字段值,目前我们能做的操作就是点击每条数据前面的 id,他会进入这条数据的详情页,每个字段都是默认可修改的。
指定字段点击进入编辑页
我们也可以指定某个,或者某几个字段进入这条数据的详情页进行编辑,用到的属性是 list_display_links,这个属性的值默认是 id 主键字段,但如果我们想点击 id 和 name 字段的时候都进入详情页,可以如下操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
list_display_links = ("id", "name",)
直接在列表页面修改字段值
如果某个字段是需要经常修改的,我们想要在列表页面就修改而不用进入数据的详情页,可以加上 list_editable 属性,比如我们直接在列表页修改 name 字段的值:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
list_editable = ("name", )
需要注意的是,list_editable 和 list_display_links 这两个属性是相斥的,也就是说这两个的字段列表不能拥有同一个字段值。
详情页字段的显示与否
点击进入数据的编辑详情页,默认所有字段是可以修改的,如果想要某些字段在详情页显示或者不显示,可以使用 fields 和 exclude 属性,分别表示显示和不显示的字段。
显示 name 和 is_published 字段:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
fields = ("name", "is_published")
隐藏 name 和 is_published 字段:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
exclude = ("name", "is_published")
字段仅可读
有一些比较重要的字段,如果在详情页不希望能够被修改,可以使用 readonly_fields 属性,比如不希望 name 字段被修改:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
readonly_fields = ("name",)
重启系统后,就可以在列表页看到 name 字段没有修改框,为仅可读状态了。
注意: 需要提醒的一点是,上面所有的添加字段属性的操作的值都需要是列表或者元组。
save_as 属性
save_as,这是一个在数据详情页保存时的属性,目前进入数据的详情页,右下角有三个按钮,左边的第一个是 save_and_add_another
,意思是保存操作之后会自动进入新的页面,可用于创建数据。
当我们设置 save_as=True 之后:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
save_as = True
再看这三个按钮,第一个按钮就会变成 save as new
,意思是在原数据上修改了之后,点击可以保存为一条新数据,原数据保持不变。
这个操作过程可以理解成我们前面一篇笔记中介绍如何新建一条数据的方式,就是在原数据上将 id 字段变成 None 然后进行 save 操作,就会在原数据的基础上创建一条新数据。
这个过程可以去看 Django笔记的第十八篇中自增的主键那一段。
5、列表页的执行操作
在列表页,目前仅有一个可供执行的操作,那就是选中 id 那一栏的数据之后,点击 action 旁边的下拉框,有一个 delete 操作,意思是删除选中的数据:
快速搜索过滤操作
对于某些值的种类比较少的数据,比如 is_published 字段,或者日期字段,想要实现快速搜索的操作,可以使用 list_filter 属性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
list_filter = ("is_published", "pub_datetime")
重启系统后可以看到列表页面右侧出现了一个筛选列表:
对于非日期字段,这里有一些固定的日期的选择,对于其他字段,则是会列出所有字段值作为筛选项。
指定字段搜索
如果想要对某个或者某几个字段进行模糊搜索,可以使用 search_fields 属性,比如想要搜索 name 和 pub_datetime 字段:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
search_fields = ("name", "pub_datetime")
重启系统后,页面的左上角会出现一个搜索框,比如我们搜索 python
,就会去查找 name 和 pub_datetime 字段中包含 python
的数据。
如果我们搜索的时候使用空格将搜索的关键字分隔开,那么系统会自动为我们进行 split() 操作,然后搜索,比如这里我们搜索的是 python 2021
,那么系统转化的 sql 就会是:
where (name like '%python%' or pub_datetime like '%python%') and (name like '%2021%' or pub_datetime like '%2021%')
如果希望搜索的内容是一个整体,可以使用单引号或者双引号括起来 'python 2021'
日期分级筛选
前面介绍了一个快速搜索过滤的操作,这里针对于日期字段介绍一下另一种筛选过滤的方式,比如我们对 pub_datetime 字段进行操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
date_hierarchy = "pub_datetime"
重启系统后,可以在页面左上角看到 2021,2022,2023 几个年份,都是根据当前表里的数据统计出来的结果,然后点击进入相当于是进行了一次年份的筛选,在第二层页面继续点击选择则是一次新的筛选:
save_model()
前面在 Django笔记第十八篇中有介绍过一条数据的保存 save() 操作的继承处理,我们可以通过自定义一些逻辑使得数据在保存前进行一些操作,在这里,save_model() 的操作也可以提供同样的功能:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
def save_model(self, request, obj, form, change):
print("do something")
super().save_model(request, obj, form, change)
actions 自定义执行任务
假设说我们想要实现一些批量执行的操作,比如选中列表页某些数据,将 is_published 字段批量更新成 True(即已发布),我们就可以用到 actions 来实现。
目前在页面的左上角有一个 action 和旁边的下拉框,系统实现了一个默认的函数逻辑,即删除选中项,我们可以来实现一个更新选中项的功能:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
actions = ["make_published"]
@admin.action(description="make queryset published")
def make_published(self, request, queryset):
queryset.update(is_published=True)
使用 admin.action 作为装饰器来装饰一个函数,然后将函数名称作为值放入 actions 列表中,在这里 queryset 参数即为页面选中的数据,它是一个 queryset 类型,所以这里可以直接进行 update() 操作。
如果想执行一些更深入的操作,我们也可以对 request 参数进行操作解析,它即为我们前端选中执行传过来的请求。
重启系统后,刷新页面,点开 action 旁边的下拉框,就可以看到我们定义的函数了,选中数据,点击旁边的 Go
按钮即可执行。
可以定义多个执行函数,记得添加到 actions 列表进行注册即可。
如果想获取更多后端相关文章,可扫码关注阅读: