(9) Django - Admin后台系统

Django内置了强大的Admin后台系统,并且是默认启用的。在根目录的urls.py中可以看到Admin的URL地址信息,在浏览器上输入http://127.0.0.1:8000/admin就能访问Admin后台系统。

中文语言设置

初次访问Admin后台系统时,可能显示的会是英文,这时候只需要到根目录的settings.py中设置一下即可,有两种方法:

  • 设置中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    #使用中文
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
  • 设置LANGUAGE_CODE
LANGUAGE_CODE = 'zh-Hans'

创建超级用户

访问后台系统还需要输入用户名和密码。因此,我们还需要创建一个超级用户。在创建用户之前,确保项目的模型在数据库中有相应的数据表。创建方法仍然由Django的manage.py完成,在项目目录下输入以下命令:

E:\mysite>python manage.py createsuperuser
Username (leave blank to use 'user'): root
Email address: 12345678@qq.com
Password:
Password (again):
The password is too similar to the email address.
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

依次输入用户名root,email、password,如果密码过于简单,还会提示是否仍然创建,输入y,创建超级用户成功!
使用刚才创建的账户和密码即可进入Admin后台管理系统的页面。


image.png

注册模型

在Admin后台系统中,可以看到站点管理下只有用户和组的管理,这是Django内置的认证系统。要将index中自定义的模型Product和Type展示在后台系统中,则需要在index的admin.py中添加如下代码:

from django.contrib import admin
from .models import *

# Register your models here.
#方法一:将模型直接注册到admin后台。
# admin.site.register(Product)

#方法二:自定义ProductAdmin类并继承ModelAdmin
#注册方法1,使用Python装饰器将ProductAdmin和模型Product绑定并注册到后台
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    #设置显示的自断
    list_display = ['id', 'name', 'weight', 'size', 'type']
#注册方法2
admin.site.register(Product, ProductAdmin)

日常开发中,一般采用方法二来实现注册。


image.png

刷新Admin后台系统页面,可以看到站点管理出现了INDEX,代表项目index,INDEX下的Products是index中的模型Product,对应数据表index_product。

Admin的基本设置

虽然我们成功将数据表index_product成功展现在站点管理的页面,但对一个不会网站开发的使用者来说,可能无法理解INDEX和Products的函数,因此,还需要将INDEX和Product转换成具体的中文内容。将INDEX和Products设置中文显示需要分别使用不同的方法实现,因为INDEX和Products在项目中分别代表不同的意思,前者是一个App的命名,后者是一个App中定义的模型。

设置App名中文显示

首先实现INDEX的中文显示,主要由App的__init__.py文件实现:

#index 的 __init__.py文件
from django.apps import AppConfig
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__)
    verbose_name = '网站首页'

当项目启动时,程序会从初始化文件__init__获取重写的IndexConfig类,类属性verbose_name用于设置INDEX的中文内容。

设置模型中文显示

接下来将Products设置中文显示,在models.py中设置类Meta的类属性verbose_name_plural即可实现。

#models.py
class Product(models.Model):
    id = models.AutoField(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)

    #设置返回值
    def __str__(self):
        return self.name
    class Meta:
        #如只设置verbose_name,在Admin会显示为“产品信息s”
        verbose_name = '产品信息'
        verbose_name_plural = '产品信息'
设置Admin网页标题信息

除此之外,还可以进一步完善Admin网页标题信息,在App的admin.py中添加以下代码

#修改title和header
admin.site.site_title = '手机后台管理'
admin.site.site_header = '我的手机后台'
image.png
表头信息的中文设置

然后我们点击产品信息,进入模型Product的数据页面,会发现表头信息显示的是模型的字段,要让数据表头以中文的形式展现,我们需要在定义模型的字段时,添加参数verbose_name。该参数作为第一个参数时,可以省略参数名,在其他位置时必须加上参数名verbose_name。

#index 的 models.py
class Product(models.Model):
    id = models.AutoField(verbose_name='序号',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='产品类型')
image.png
产品类型的中文显示

上图可以发现,产品类型的数据是一个模型Type对象。因此,在模型Type中定义__str__函数,设置模型的返回值。

#index 的 models.py
class Type(models.Model):
    id = models.AutoField('序号', primary_key=True)
    type_name = models.CharField('产品类型', max_length=20)
    #设置返回值
    def __str__(self):
        return self.type_name
image.png
设置搜索框、过滤器、排序方式、时间选择器等

当一个数据表中存储了成千上万的数据时,查找功能就时必要的。Django在admin.py的ProductAdmin类中设置属性search_fields就可以实现搜索查找。

#admin.py 中的 ProductAdmin类
@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']
    #设置时间选择器,如字段中有时间格式才可以使用
    date_hierarchy = Field
    #在添加新数据时,设置可添加数据的字段
    fields = ['name', 'weight', 'size', 'type']
    #设置只读字段,在修改或新增数据时,使其无法设置
    readonly_fields = ['name']

Admin的二次开发

上述都是Admin的基本设置,但每个网站的功能和需求都是各不相同的,所以Admin后台功能也有所差异。因此,通过重写ModelAdmin的方法可以实现Admin的二次开发,满足多方面的开发需求。

函数 get_readonly_fields

函数get_readonly_fields 和属性readonly_fields的功能相似,不过比后者更强大。使用get_readonly_fields可以实现不同的用户角色来决定字段的可读属性,如:

#admin.py 中的 ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    #重写get_readonly_fields函数,设置超级用户和普通用户的权限
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            self.readonly_fields = []
        else:
            self.readonly_fields = ['name']
        return self.readonly_fields

设置字段格式

在后台预览模型Product的数据信息时,数据表的表头是由属性 list_display所定义的。如果要对某些字段的数据进行特殊处理,如设置数据的字体颜色,以模型Product的type字段为例:

#index 的 models.py 的ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    #自定义函数,设置字体颜色
    def colored_type(self):
        if '手机' in self.type.type_name:
            color_code = 'red'
        elif '平板电脑' in self.type.type_name:
            color_code = 'blue'
        elif '智能穿戴' in self.type.type_name:
            color_code = 'green'
        else:
            color_code = 'yellow'
        return format_html('<span style="color: {};">{}</span>',color_code,self.type)

    #设置Admin的标题
    colored_type.short_description = '带颜色的产品类型'

然后再到admin.py的ProductAdmin类中添加自定义字段

#admin.py 的 ProductAdmin类中
#添加自定义字段,colored_type来自于模型Product
list_display.append('colored_type')

运行结果如下:


image.png

函数 get_queryset

函数 get_queryset根据不同用户角色设置数据的访问权限,该函数可以将一些重要的数据进行过滤。以模型Product为例,在admin.py的类ProductAdmin中重写函数get_queryset。

#admin.py 的 ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    #重写get_queryset函数,根据当前用户名设置数据访问权限,非超级用户仅能读取前5条数据
    def get_queryset(self, request):
        qs = super(ProductAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        else:
            return qs.filter(id__lt=6)
image.png

函数formfield_for_foreignkey

该函数用于在新增或修改数据的时候,设置外键的可选值。如果在模型中将某字段定义为外键类型,当新增数据时,该字段为一个下拉框控件,下拉框中的数据来自于该字段所指向的模型。
如果想对下拉框中的数据实现过滤功能,可以对函数formfield_for_foreignkey进行重写。

#admin.py 的 ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    #重写formfield_for_foreignkey函数,新增或修改数据时,设置外键可选值
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        #一个模型可以定义多个外键,所以首先要判断外键名
        if db_field.name == 'type':
            if not request.user.is_superuser:
                kwargs["queryset"] = Type.objects.filter(id__lt=4)#非超级用户返回前3个类型
        return super(admin.ModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
image.png

函数 save_model

函数save_model是在新增或修改数据时,点击保存按钮所触发的功能,该函数主要对输入的数据进行入库和更新处理。如果想在这功能中加入一些特殊的功能需求,可以对该函数进行重写。比如对数据的修改实现一个日志记录,那么函数save_model的实现代码如下:

#admin.py 的 ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    #修改保存方法
    def save_model(self, request, obj, form, change):
        if change:
            #获取当前用户名
            user = request.user
            #使用模型获取数据, pk代表具有主键属性的字段
            name = self.model.objects.get(pk=obj.pk).name
            #使用表单获取数据
            weight = form.cleaned_data['weight']
            #写入日志文件
            f = open('e://mysite/mysite_log.txt','a')
            f.write('产品:' + str(name) + ',被用户:' + str(user) + ' 修改' + '\r\n')
            f.close()
        else:
            pass
        #使用super可使自定义save_model既保留父类已有功能又添加自定义功能
        super(ProductAdmin, self).save_model(request, obj, form, change)

此外,还有数据删除所执行的函数delete_model,代码如下:

#admin.py 的 ProductAdmin类
class ProductAdmin(admin.ModelAdmin):
    # ...
    #以上的代码省略
    def delete_model(self, request, obj):
        pass
        super(ProductAdmin, self).delete_model(request, obj)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353