第八章 admin后台系统
admin后台系统也成为网站后台管理系统,主要用于对网站前台的信息进行管理,如文字、图片、影音和其他日常使用文件的发布、更新、删除等操作,也包括功能信息的统计和管理,如用户信息、订单信息和访客信息等。简单来说,即使对网站数据库和文件的快速操作和管理系统,以使网页内容能够及时得到更新和调整。
8.1 走进admin
在INSTALLED_APPS中已配置了Django的Admin后台系统,如果网站不需要Admin系统,可以将配置信息删除,这样可以减少程序对系统资源的占用。此外,在根目录的urls.py中也可以看到Admin的URL地址信息,我们在浏览器上输http://127.0.0.1:8000/admin就能访问Admin后台系统,如下图:
在访问Admin后台系统时,首先需要输入用户的账号和密码登录才能进入后台管理界面。创建用户的账号和密码之前,必须确保项目的模型在数据库中有相应的数据表,以MyDjango为例,项目的数据表如图:
如果Admin后台系统以英文的形式显示,那么我们还需要在项目的settings.py中设置MIDDLEWARE中间件,将后台内容以中文形式显示。添加中间件是有先后顺序的,具体如上图。
完善上述设置后,下一步就是创建用户的账号和密码,创建方法由Django的管理工具manage.py完成,在PyCharm的Terminal模式下输入创建指令,代码如下:
(py3_3) E:\test5\MyDjango>python manage.py createsuperuser 用户名 (leave blank to use 'aoc'): root 电子邮件地址: Password: Password (again): 密码长度太短。密码必须包含至少 8 个字符。 这个密码太常见了。 Bypass password validation and create user anyway? [y/N]: y Superuser created successfully.
在创建用户信息时,用户名和邮箱地址可以为空,如果用户名为空会默认使用计算机的用户名,而设置用户密码时,输入的密码不会显示在计算机的屏幕上。完成用户创建后,打开数据表auth_user可看到新增了一条用户信息,如下图:
在Admin登录页面上使用刚创建的账号和密码登录,即可进入Admin后台系统的页面,如下图:
在Admin后台系统中可以看到,主要功能分为站点管理、认证和授权、用户和组,说明如下:
1、站点管理是整个网站的App管理界面,主要管理Django的App下所定义的模型
2、认证和授权是Django内置的认证系统,也是项目的一个App。
3、用户和组是认证和授权所定义的模型,分别对应数据表auth_user和auth_user_groups。
在MyDjango中,已在index中定义了模型Product和Type,分别对应数据表index_product和index_type。若想将index定义的模型展示在Admin后台系统中,则需要在index的admin.py中添加以下代码:
from django.contrib import admin from .models import * # Register your models here. #方法一 #将模型直接注册到admin后台 admin.site.register(Product) #方法二: #自定义ProductAdmin类并继承ModelAdmin #注册方法一,使用Python装饰器将ProductAdmin和模型Product绑定并注册到后台 @admin.register(Product) class ProductAdmin(admin.ModelAdmin): #设置显示的字段 list_display = ['id', 'name', 'weight', 'size', 'type',] #注册方法二 #admin.site.register(Product, ProductAdmin)
上述代码以两种方法将数据表index_product注册到Admin后台系统,方法一是基本的注册方式;方法二是通过类的继承方式实现注册。日常的开发都是采用第二种方法实现的,实现过程如下:
1、自定义ProductAdmin类,使其继承ModelAdmin。ModelAdmin主要设置模型信息如何展现在Admin后台系统中。
2、将ProductAdmin类注册到Admin后台系统中有两种方法,两者都是将模型Product和ProductAdmin类绑定并注册到Admin后台系统。
以ProductAdmin类为例,刷新Admin后台系统页面,看到站点管理出现INDEX,代表项目的index,INDEX下的Products是index中的模型Product,对应数据表index_product,如下图:
8.2 Admin的基本设置
在上一节中,我们将数据表index_product成功展现在站点管理的页面,但对一个不会网站开发的使用者来说,可能无法理解INDEX和Products的含义,而且用英文表示也会影响整个网页的美观。因此,我们需要将INDEX和Products设置中文显示需要分别使用不同的方法实现,因为INDEX和Products在项目中分别代表不同的意思,前者是一个App的命名,后者是一个App中定义的模型。
首先实现INDEX的中文显示,主要App的__init__.py文件实现,实现代码如下:
#INDEX设置中文,代码编写在App(index)的__init__.py文件中 from django.apps import AppConfig from .apps import * import os #修改App在Admin后台显示的名称 #default_app_config的值来自apps.py的类名 default_app_config = 'index.IndexConfig' #获取当前App的命名 def get_current_app_name(_file): return os.path.split(os.path.dirname(_file))[-1] #重写类IndexConfig class IndexConfig(AppConfig): name = get_current_app_name(__file__) verbost_name = '网站首页'
当项目启动时,程序会从初始化文件__init__获取重写的IndexConfig类,类属性verbose_name用于设置INDEX的中文内容。
然后将Products设置中文显示,在models.py中设置类Meta的类属性verbose_name_plural即可实现。值得注意的是,Meta的类属性还有verbase_name,两者都能设置Products的中文内容,但verbose_name是以复数形式表示的,如将Products设置为"产品信息",verbose_name会显示为"产品信息s",实现代码如下:
#Products设置中文,代码编写在models.py文件中 #创建产品信息表 #设置字段中文名,用于Admin后台显示 class Product(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) weight = models.CharField(max_length=20) size = models.CharField(max_length=20) type = models.ForeignKey(Type, on_delete=models.CASCADE,verbose_name='产品类型') #设置返回值 def __str__(self): return self.name class Meta: #如只设置verbose_name,在Admin会显示为"产品信息s" verbose_name = '产品信息' verbose_name_plural = verbose_name
除此之外,我们还可以进一步完善Admin网页标题信息,在App的admin.py文件中编写以下代码:
#修改title和header admin.site.site_title = 'MyDjango后台管理' admin.site.site_header = 'MyDjango' #自定义ProductAdmin类并继承ModelAdmin @admin.register(Product) class ProductAdmin(admin.ModelAdmin): #设置显示的字段 list_display = ['id', 'name', 'weight', 'size', 'type',]
上述例子实现了INDEX、Products的中文设置和Admin网页标题内容的修改,分别由index的初始化文件__init__、模型文件models.py和admin.py实现。运行MyDjango项目,admin管理页面如下图:
当单击图中的产品信息时,网页会进入模型Product的数据页面,数据以表格的形式展示。从表格上可以发现,表头信息代表模型的字段,并且表头是以中文的形式展现的。如果细心观察就会发现,在上述例子中,models.py所定义的模型Product的字段设置了中文内容,中文内容是字段参数verbose_name的参数值,所以模型Product的数据表头才以中文的形式展现,如下图:
从图中可以发现,产品类型的数据是一个模型Type对象,与第7章的表单下拉框数据设置是同一个问题。因此,在模型Type中定义__str__函数,设置模型的返回值,代码如下:
#创建产品分类表 #设置字段中文名,用于Admin后台显示 class Type(models.Model): id = models.AutoField('序号',primary_key=True) type_name = models.CharField('产品类型',max_length=20) #设置返回值,若不设置,则默认返回Type对象 def __str__(self): return self.type_name
在浏览器上刷新当前网页,可以发现产品类型的数据变为模型字段Type_name的数据,如下图:
当一个数据表中存储了成千上万的数据,在Admin中查找该表的某条数据信息时,如果不使用一些查找功能,是无法精准地找到需要的数据信息的。为解决这个问题,可以在admin.py中进一步优化ProductAdmin,优化代码如下:
#admin.py配置文件 from django.contrib import admin from .models import * @admin.register(Product) class ProductAdmin(admin.ModelAdmin): #设置模型字段,用于Admin后台数据的表头设置 list_display = ['id', 'name', 'weight', 'size', 'type',] #设置可搜索的字段并在Admin后台数据生成搜索框,如有外键,应使用双下划线连接两个模型的字段 search_fields = ['id', 'name', 'type__type_name'] #设置过滤器,在后台数据的右侧生成导航栏,如有外键,应使用双下划线连接两个模型的字段 list_filter = ['name', 'type__type_name'] #设置排序方式,['id']为升序,降序为['-id'] ordering = ['id'] #设置时间选择器,如字段中有时间格式才可以使用 #data_hierarchy = Field #在添加新数据时,设置可添加数据的字段 fields = ['name', 'weight', 'size', 'type'] #设置可读字段,在修改或新增数据时使其无法设置 readonly_fields = ['name']
上述代码中,ProductAdmin类分别设置list_display、search_fields、list_filter、ordering、date_hierarchy、fields和readonly_fields属性,每个属性的作用在代码注释已有说明。除了date_hierarchy之外,其他属性值还可以使用元素格式表示。在ProductAdmin类新增的属性都在页面中生成相应的功能,如下图:
值得注意的是,如果readonly_fields和fields属性设置了模型的同一个字段,那么在新增数据的时候,该模型字段是无法输入数据的。例如上述设置,readonly_fields和fields同时设置了name字段,在新增数据时,该字段的值默认为空并且无法输入数据,如下图:
8.3 Admin的二次开发
前面的章节讲述了Admin的基本设置,但实际上每个网站的功能和需求都是各不相同的,这也导致了Admin后台功能有所差异。因此,通过重写ModelAdmin的方法可以实现Admin的二次开发,满足多方面的开发需求。
8.3.1 函数get_readonly_fields
函数get_readonly_fields和属性readonly_fields的功能相似,不过前者比后者更为强大。比如使用函数get_readonly_fields实现不同的用户角色来决定字段的可读属性,实现代码如下:
class ProductAdmin(admin.ModelAdmin): #设置模型字段,用于Admin后台数据的表头设置 list_display = ['id', 'name', 'weight', 'size', 'type',] #设置可搜索的字段并在Admin后台数据生成搜索框,如有外键,应使用双下划线连接两个模型的字段 search_fields = ['id', 'name', 'type__type_name'] #设置过滤器,在后台数据的右侧生成导航栏,如有外键,应使用双下划线连接两个模型的字段 list_filter = ['name', 'type__type_name'] #设置排序方式,['id']为升序,降序为['-id'] ordering = ['id'] #设置时间选择器,如字段中有时间格式才可以使用 #data_hierarchy = Field #在添加新数据时,设置可添加数据的字段 fields = ['name', 'weight', 'size', 'type'] #设置可读字段,在修改或新增数据时使其无法设置 readonly_fields = ['name'] #重写get_readonly_fields函数,设置超级用户和普通用户的权限 def get_readonly_fields(self, request, obj=None): if request.user.is_superuser: self.readonly_fields = [] return self.readonly_fields