• 玩转Django2.0---Django笔记建站基础八(admin后台系统)


    第八章  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:	est5MyDjango>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
    View Code

        函数get_readonly_fields首先判断当前发生请求的用户是否为超级用户,如果符合判断条件,将重新设置readonly_fields属性,使当前用户具有全部字段的编辑权限。其中,函数参数request是当前用户的请求对象,参数obj是模型对象,默认值为None。

        在浏览器上通过切换不同的用户登录,可以发现在新增或者修改数据的时候,不同的用户身份对字段name的操作权限有所不同,具体如下:

       8.3.2  设置字段格式

        在Admin预览模型Product的数据信息时,数据表的表头是由属性list_display所定义的,每个表头的数据都来自于数据库,并且数据以固定的字体格式显示在网页上。若要对某些字段的数据进行特殊处理,如设置数据的字体颜色,以模型Product的type字段为例,将该字段的数据设置为不同的颜色,实现代码如下:

    在models.py的模型Product
    
    from django.utils.html import format_html
    
    
    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会显示为产品信息
            verbose_name = '产品信息'
            verbose_name_plural = verbose_name
    
        #自定义函数,设置字体颜色
        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.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        ......省略代码......
    
        def get_readonly_fields(self, request, obj=None):
            if request.user.is_superuser:
                self.readonly_fields = []
            return self.readonly_fields
        
        #添加自定义字段,在属性list_display中添加自定义字段colored_type,colored_type来自于模型Porduct
        list_display.append('colored_type')

      从上述代码可以看到,设置字段的数据格式主要由文件models.py和admin.py实现,说明如下:

        1、在models.py的模型Product中定义函数colored_type,函数名可以自行命名,该函数通过判断模型字段的数据内容,从而返回不同的字体颜色。

        2、然后在admin.py的类ProductAdmin的属性list_display中添加模型Product的函数colored_type,使该函数以表头的形式显示在Admin后台的数据信息页面上。运行结果如下图:

       8.3.3  函数get_queryset

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

    #admin.py的类ProductAdmin
    #根据当前用户名设置数据访问权限
    @admin.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        ......省略部分代码......
        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)

        分析上述代码可知,自定义函数get_queryset的代码说明如下:

          1、首先通过super方法来获取父类ModelAdmin的函数get_queryset所生成的查询对象,该对象用于查询模型Product的全部数据。

          2、然后判断当前用户的用户身份,如果为超级用户,函数返回模型Product的全部数据,否则只返回模型Product的前5条数据。运行结果如下图:

     图   设置数据访问权限

      8.3.4  函数formfield_for_foreignkey

        函数formfield_for_foreignkey用于在新增或修改数据的时候,设置外键的可选值。如果在模型中将某字段定义为外键类型,当新增数据时,该字段为一个下拉框控件,下拉框中的数据来自于该字段所指向的模型,如下图:

         如果想要对下拉框的数据实现过滤功能,可以对函数formfield_for_foreignkey进行重写,代码如下:

    在admin.py的类ProductAdmin
    @admin.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        ......省略部分代码......
        #新增或修改数据时,设置外键可选值
        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)
            return super(admin.ModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

        上述代码通过重写函数formfield_for_foreignkey,实现下拉框的数据过滤,实现说明如下:

          1、参数db_field是模型Product的外键对象,一个模型可以定义多个外键,因此函数首先对外键名进行判断。

          2、然后判断当前用户是否为超级用户,参数request是当前用户的请求对象。

          3、如果当前用户为普通用户,则设置参数kwargs的queryset,参数kwargs是以字典的形式作为函数参数,queryset是参数kwargs的键。

          4、最后将设置好的参数kwargs传递给父类的函数formfield_for_foreignkey重新执行。运行结果如下:

    设置外键可选值

      8.3.5  函数save_model

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

        #修改保存方法
        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://MyDjango_log.txt', 'a')
                f.write('产品: '+str(name)+', 被用户: '+str(user)+'修改'+'
    ')
                f.close()
            else:
                pass
            #使用super可使自定义save_model即保留父类已有的功能又添加自定义功能
            super(ProductAdmin, self).save_model(request, obj, form, change)

        上述代码中,函数save_model的功能说明如下:

          1、首先判断参数change是否为True,若为True,则说明当前操作为数据修改,反之为新增数据。

          2、分别从三个函数参数中获取相关的数据内容。参数request代表当前用户的请求对象,参数obj代表当前数据所对应的模型对象,参数form代表Admin的数据修改页面所对应的数据表单。

          3、然后将所获取的数据写如文本文件,实现简单的日志记录功能。

          4、最后使用super方法使重写函数save_model执行原有函数save_model的功能,对数据进行入库和变更处理。若将此代码注释,当触发从写函数时,程序只执行记录功能,并不执行数据入库和变更处理。

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

        def delete_model(self, request, obj):
            pass
            super(ProductAdmin, self).delete_model(request, obj)

      8.3.6  自定义模板

        Admin后台系统的HTML模板是有Django提供的,我们可以在Django的安装目录下找到Admin模板所在的路径(Libsite-packagesdjangocontribadmin emplatesadmin)。如果想要对Admin的模板进行自定义更改,可直接修改Django里面的Admin模板,但一般不提倡这种方法。如果一台计算机同时开发多个Django项目,这样会影响其他项目的使用。除了这种方法之外,还可以利用模板继承的方法实现自定义模板开发。我们对MyDjango项目的目录架构进行调整,如下图:

         在项目中创建模板文件夹templates,在templates下依次创建文件夹admin和index,说明如下:

          1、文件夹admin代表该文件里的模板用于Admin后台管理系统,而且文件夹必须命名为admin。

          2、文件夹index代表项目的App,文件夹的命名必须与App的命名一致。该文件夹存放模板文件change_form.html,并且模板文件只适用于index的后台数据。

          3、如果将模板change_form.html放在admin文件夹下,说明该文件适用于当前项目的所有App。

        值得注意的是,在项目中创建文件夹templates时,切勿忘记在项目settings.py中配置templates的路径信息。最后在模板change_form.html中编写一下代码:

    {% extends "admin/change_form.html" %}
    {% load i18n admin_urls static admin_modify %}
    {% block object-tools-items %}
        {% if request.user.is_superuser %}
            <li>
                {% url opts|admin_urlname:'history' original.pk|admin_urlquote as history_url %}
                <a href="{% add_preserved_filters history_url %}"></a>
            </li>
            #判断符结束
        {% endif %}
        {% if has_absolute_url %}
            <li><a href="{{ absolute_url }}" class="viewsitelink">{% trans "View on site" %}</a></li>
        {% endif %}
    {% endblock %}

        从代码可以看到,自定义模板change_form.html的代码说明如下:

          1、自定义模板change_form.html首先继承自Admin源模板change_form.html,自定义模板的命名必须与源模板的命名一致。

          2、例如源模板admin/change_form.html导入了标签{% load i18n admin_urls static admin_modify %},因此自定义模板change_form.html也需要导入该模板标签。

          3、通过使用block标签实现源模板的代码重写。我们查看源模板的代码发现,模板代码以{%  block xxx  %}形式分块处理,将网页上不同的功能都一一区分了。因此,在自定义模板中使用block标签可对某个功能进行自定义开发。

        项目运行时,程序优先查找项目文件夹admin的模板文件,若找不到相应的模板文件,再从Django中的admin源模板查找。在上述例子中,使用超级用户和普通用户分别进入产品信息的数据修改页面时,不同的用户角色所返回的页面会有所差异,如下图:

     

       除了上述例子之外,Django的Admin后台管理系统还提供了许多功能函数,具有函数的说明以及使用。

    8.4  本章小结

      Admin后台管理系统也成为网站后台管理系统,主要用于对网站前台的信息进行管理,如文字、图片、影音和其他日常使用文件的发布、更新、删除等操作,也包括功能信息的统计和管理,如用户信息、订单信息和访客信息等。简单来说,就是对网站数据库和文件的快速操作和管理系统,以使网页内容能够及时得到更新和调整。

      Admin的基本设置有App的中文设置、模型的中文设置、Admin网页标题和模型数据设置,说明如下:

        1、App的中文设置:在App的初始化文件__init__中重写IndexConfig类,设置类属性verbose_name即可实现。

        2、模型的中文设置:在App的模型文件models.py中设置类Meta的类属性verbose_name_plural即可实现。

        3、Admin网页标题:在App的admin.py中分别设置属性admin.site.site_title和admin.site.site_header即可实现。

        4、模型数据设置:在App的admin.py中自定义类并且继承父类admin.ModelAdmin,通过重写父类的属性和方法可实现自定义模型数据设置。

      Admin的二次开发主要对父类admin.ModelAdmin中已有的方法进行重写,实现自定义开发。常用的方法如下:

        1、函数get_readonly_fields通过重写该函数,可以根据用户身份来控制数据的写入权限。

        2、设置字段格式:首先在模型文件models.py中自定义函数并将处理后的模型字段作为函数返回值,然后将自定义的函数写入admin.py的类属性list_display中。

        3、函数get_queryset根据不同用户角色设置数据的访问权限,该函数可以将一些重要的数据进行过滤。

        4、函数formfield_for_foreignkey在新增或修改数据的时候,设置外键的可选值(下拉框的数据内容)。

        5、函数save_model是在新增或修改数据的时候,单击"保存"按钮所触发的功能,该函数主要对输入的数据进行入库和更新处理。

        6、自定义模板通过模板继承的方法实现Admin后台界面开发,可以根据需求改变后台界面的样式和功能。

  • 相关阅读:
    Pyton项目打包成exe文件
    App数据指标
    电商基础指标体系
    Matplotlib复杂作图
    Sklearn之聚类分析
    Seaborn可视化
    Matplotlib可视化2
    Matplotlib可视化1
    Pandas可视化
    Linux常用指令(3)
  • 原文地址:https://www.cnblogs.com/zhaop8078/p/11568092.html
Copyright © 2020-2023  润新知