> For the complete documentation index, see [llms.txt](https://close.gitbook.io/yun-wei-bi-ji/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://close.gitbook.io/yun-wei-bi-ji/python/django/3django-hou-tai-ji-chu-yong-fa.md).

# 3、Django后台基础用法

### **1、注册表**

表必须在admin.py中注册后才能在界面上显示，所以注册表时第一步，一般代码如下：

```
from django.contrib import admin
from djangoTestApp.models import Student,Score#导入表

# Register your models here.

admin.site.register(Student)
admin.site.register(Score)
```

上面代码把之前建的3张表都注册了

### **2、列表中显示列（list\_display）**

之前讲过，就是在模型管理中使用list\_display显示

```
from django.contrib import admin
from djangoTestApp.models import Student,Score

# Register your models here.
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age',)class ScoreAdmin(admin.ModelAdmin):
    list_display = ('No','Name','Course','Score')

admin.site.register(Student,StudentAdmin)
admin.site.register(Score,ScoreAdmin)
```

上面创建的样式类需要继承admin.ModelAdmin类，名称一般都是表名+Admin

一般情况下，如果有相同的名称时，list\_display按照下面顺序解释元素：

★模型中表的字段

★callabled类型（自定义 函数）

★ModelAdmin属性

★模型属性

### **3、编辑时显示列（fields）**

即在增加or编辑界面显示fields中的字段，如下为当前Student表在编辑界面展示的字段：

![](/files/9QCiYDarYigbm3co0ujd)

上面左图为增加界面，右图为修改界面，显示了Student的4个字段

在admin.py中加上fields字段只显示学号、姓名和年龄，如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    fields = ('No','Name','Age')#编辑界面只显示No、Name和Age
```

这样在编辑界面只有这三个字段，少了‘性别’：

![](/files/fsMTPgKTGQdW5iRxQnRr)

fields还有调整列的顺序的功能，比如把No和Name对调一下

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    fields = ('Name','No','Age',)#No和Name顺序对调
```

在界面上显示如下：

![](/files/CT9S0tAUtOVvZNDAqQNk)

如上图，学号和姓名已经调整了位置。

fields还有使字段分布在同一行的功能，直到一行满了为止。比如说要把姓名和学号放到一排，那么可以如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    fields = (('Name','No',),'Age',)#Name和No一组，在同一行显示
```

界面上如下图所示：

![](/files/51bQ2YZBOqK3z6P71lIU)

### **4、编辑时不显示列（exclude）**

同fields字段相反，在exclude中的字段将不会显示。使用时不要把fields和exclude同时使用

同上，如果不需要显示Sex字段，也可以直接写成如下，效果是一样的

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = ('No','Name','Age',)
    exclude = ('Sex',)#记得元祖需要在后面加个逗号，不然会报错
```

### **5、编辑时页面布局（fieldsets）**

比如说把No和Name作为‘基本信息’字段集，把Age和Sex作为‘高级信息’字段集，代码可以做如下调整

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = (('Name','No',),'Age',)
    #exclude = ('Sex',)
    fieldsets = (
        ('基本信息',{
                'fields':('No','Name',),
            },
        ),
        ('高级信息',{
                'fields':('Sex','Age',),
            }
        )
    )
```

说明下fields和fieldsets不能同时存在，系统会报错导致打不开。

上面代码在界面上展示样式如下：

如果不需要‘基本信息’这一行，可以在fieldsets中把‘基本信息’修改为None：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = (('Name','No',),'Age',)
    #exclude = ('Sex',)
    fieldsets = (
        (None,{#不显示
                'fields':('No','Name',),
            },
        ),
        ('高级信息',{'fields':('Sex','Age',),
            }
        )
    )
```

界面展示如下：

![](/files/hziNM2EVg5sFOz5142nD)

也可以把不重要的信息折叠起来，这时会用到字段集的参数classes，如下把高级信息折叠起来：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = (('Name','No',),'Age',)
    #exclude = ('Sex',)
    fieldsets = (
        (None,{
                'fields':('No','Name',),
            },
        ),
        ('高级信息',{
                'classes':('collapse',),#把‘高级信息’默认折叠起来
                'fields':('Sex','Age',),
            }
        )
    )
```

在界面上展示如下，可以通过点击‘show’展开：

![](/files/MdHVxKUyZUR4OoOaAvYF)

classes还有另外一个样式：wide，即字段填写有更大的控件。

字段集还有属性description，即描述，如果带有此属性，则会显示在 字段集下方，如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = (('Name','No',),'Age',)
    #exclude = ('Sex',)
    fieldsets = (
        (None,{
                'fields':('No','Name',),
            },
        ),
        ('高级信息',{
                'classes':('collapse',),
                'description':'这里是高级信息的内容',#描述的内容
                'fields':('Sex','Age',),
            }
        )
    )
```

### **6、编辑时样式字段（form）**

可以通过django.forms来定义不同的样式，然后在模型管理中调用这个样式，如下在admin.py中定义一个样式

```
from django import forms#导入样式类

class StudentForm(forms.ModelForm):
    class Meta:
        exclude = ('Sex',)
```

上面代码就是让表Student不显示Age这个列，然后在StudentAdmin类中调用这个样式

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age')
    #fields = (('Name','No',),'Age',)
    #exclude = ('Sex',)
    form = StudentForm#调用自定义样式，之前的fieldsets注释掉
```

上面这样调用和在模型管理中调用exclude效果是一样的，但若模型管理中也有exclude，那么优先使用模型管理中的。

这个规则同样适用于其他样式比如fields、fieldsets等

### **7、字段样式（format\_html）**

在前面学习过字段聚合显示，这里的字段样式和之前差不多，比如把性别按照male和female分别显示蓝色和红色，具体操作如下

▲在models.py的Student表中增加如下代码：

```
from django.utils.html import format_html

class Student(models.Model):
    No = models.CharField('学号',max_length = 10)
    Name = models.CharField('姓名',max_length = 20)
    Sex = models.CharField('性别',max_length = 1,choices = SEX_CHOICE,default = 'M')
    Age = models.IntegerField('年龄')

    def colored(self):#定义显示的颜色，male显示蓝色，female显示红色
        if self.Sex == 'M':
            html =  '<span style="color: #0000FF;">{}</span>'
        else:
            html ='<span style="color: #FF0000;">{}</span>'
        return format_html(
            html,
            self.Sex,
        )
    colored.short_description = '性别'
    Sex_color = colored
```

▲在admin.py中修改展示的列

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
```

这时刷新页面，展示效果如下：

![](/files/mL3lKb5S6DEXTiY4IVE9)

### **8、非表字段可排序（admin\_order\_field）**

通过字段样式设置的字段，在展示后无法排序（即无法通过点击字段名排序），这里可以通过指定字段来排序

（多个字段组合也可以指定，通过property装饰的字段都不能参与排序）

在models.py中增加一行如下代码：

```
class Student(models.Model):
    No = models.CharField('学号',max_length = 10)
    Name = models.CharField('姓名',max_length = 20)
    Sex = models.CharField('性别',max_length = 1,choices = SEX_CHOICE,default = 'M')
    Age = models.IntegerField('年龄')
    #Color = models.CharField(max_length = 6,default='FF0000')

    def colored(self):
        if self.Sex == 'M':
            html =  '<span style="color: #0000FF;">{}</span>'
        else:
            html ='<span style="color: #FF0000;">{}</span>'
        return format_html(
            html,
            #self.Color,
            self.Sex,
        )
    colored.short_description = '性别'
    colored.admin_order_field = 'Sex'  # 指定Sex可以参与排序
    Sex_color = colored
```

```
colored.admin_order_field = '-Sex'#指定Sex可以参与排序，先反序
```

### **9、字段链接到编辑界面（list\_display\_links）**

在没有list\_display\_links字段时，默认情况list\_displapy中第一个字段具有链接到编辑界面，如果需要其他字段链接到编辑界面，则可以使用此字段，如下设置

```
class StudentAdmin(admin.ModelAdmin):
    def Age(self,obj):
        return  'xxx'
    list_display = ('NameNo','Sex_color','Age',)
    list_display_links = ('Age',)#设置年龄字段可链接到编辑界面
```

刷新界面即可看到Age字段上的数据可以点击进入编辑界面：

![](/files/bXvEdKRWRQgrFUt6P8PN)

当然也可以设置所有字段都不可以点击进入编辑页面，只要设置为None即可

```
class StudentAdmin(admin.ModelAdmin):
    def Age(self,obj):
        return  'xxx'
    list_display = ('NameNo','Sex_color','Age',)
    list_display_links = None#所有字段都不可点击进入编辑页面
```

### **10、列表可编辑字段（list\_editable）**

list\_editable允许表字段可以在列表中直接进行编辑，也可以一次编辑多条数据，如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    list_display_links = None
    list_editable = ('Age',)#年龄字段在列表界面可直接编辑
```

刷新界面后，样式如下：

![](/files/fx5GEBAUPO1ajnsf73UW)

可以看到年龄字段可以直接进行编辑，无需再到编辑界面一个个编辑。

使用list\_editable有几个限制：

★list\_editable中字段必须在list\_display中

★list\_editable中字段不能在list\_display\_links中，如果没有list\_display\_links则不能为list\_display的第一个字段（也就是可链接到编辑界面的字段，无法在列表页直接编辑）

★list\_editable不能设置非模型中表字段，也就是必须为原始表中的字段才可以设置

### **11、过滤器（list\_filter）**

显示在列表右侧的过滤器，算是快捷的过滤方法，一般用作boolean或者有限的值，如下

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    list_filter = ('Age',)#设置Age为过滤列
    list_display_links = None
    list_editable = ('Age',)
```

刷新页面后如下所示：

![](/files/9udPKiYBwl80j08bQ8pQ)

说明：非模型中原始表的列不能作为过滤对象

list\_filter还有种写法如下，感觉效果是一样的：

```
list_filter = (('Sex',admin.ChoicesFieldListFilter,),)
```

字段Sex是Choice类型，所以也可以这么写，当然还有其他类型如：RelatedFieldListFilter、BooleanFieldListFilter、ChoicesFieldListFilter、DateFieldListFilter等

### **12、最多显示个数（list\_max\_show\_all）**

在这个版本没看出来作用

### **13、每页显示条数（list\_per\_page）**

我们设置list\_per\_page=4（**默认100**），那么Student中的6条数据会显示为俩页

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    list_filter = ('Age',)
    list_per_page = 4#每页显示4条数据
    list_max_show_all = 2
    list_display_links = None
    list_editable = ('Age',)
```

刷新页面后显示如下：

![](/files/Yhm2mLT7xMmBSRKausVB)

### **14、按照列排序（ordering）**

这个是进入表之后的排序，如果不设置，则默认按照数据录入顺序排列

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex','Age',)
    list_filter = ('Age',)
    ordering = ('-Age',)#年龄按照从大到小排列
    list_per_page = 10
    list_max_show_all = 2
    list_display_links = None
    list_editable = ('Age',)
```

### **15、编辑时显示为只读（readonly\_fields）**

即在编辑界面，设置的字段为只读，不可编辑。对非模型表原始字段也生效，若readonly\_fields设置了非模型字段，则会在编辑界面显示，否则不显示

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    readonly_fields = ('Sex','NameNo')#设置性别、姓名（学号）为只读
```

刷新界面后 显示如下：

说明：在列表界面设置可编辑（list\_editable）不冲突，俩边都可以自行设置为是否可编辑

### **16、保存为新记录并停留在编辑界面（save\_as）**

默认save\_as=False，此时编辑界面有三个按钮：保存并新增、保存继续编辑、保存并跳转到列表页。

修改为True之后，保存并新增选项会修改为保存为新纪录并跳转到新纪录的编辑界面，如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    save_as = True#保存为新纪录
```

操作如下：![](/files/AqDiG7g85e5Kr57iLIFg)

### **17、保存为新纪录并跳转到列表页（save\_as\_continue）**

默认值为True，即保存并新增按钮会跳转到编辑页面，若为False则跳转到列表页面（只针对sava\_as=True时生效）

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    save_as_continue = False#跳转到列表页面
    save_as = True
```

### **18、在编辑界面顶部设置保存、删除按钮（save\_on\_top）**

默认为False，也就是在编辑界面保存、删除按钮都是在底部。若设置为True，保存、删除按钮也会存在顶部（底部按钮仍在）

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age',)
    save_on_top = True#设置删除、保存按钮在顶部
```

### **19、搜索框（search\_fields）**

默认是没有搜索框的，需要设置。在search\_fields中的字段（必须为模型表字段）必须在list\_display中存在（不一定为模型表字段），如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age')
    search_fields = ('Name',)#搜索姓名字段
```

默认情况搜索框是按照queryset中icontains进行查询，若需要精确查询等，可以在字段上加对应的条件，如，需要精确查询姓名：

```
search_fields = ('Name__exact',)#双下划线，精确查询姓名
```

其他基本和queryset中filter类似，具体可以查看[**filter()方法**](https://www.cnblogs.com/watertaro/p/10579397.html)

### **20、是否在搜索框右侧显示列表总数（show\_full\_result\_count）**

默认为True，即显示总数，如下所示：

若设置为False

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age')
    show_full_result_count = False  #设置不显示总数，只显示‘show all’
```

则如下效果：

和总数一样，show all也可以点击，然后显示所有记录

### **21、设置列表页中的列表可排序（sortable\_by）**

默认情况下模型表字段都可以排序，之前admin\_order\_field字段是让非模型表字段可排序。

这里的sortable\_by的的优先级高于admin\_order\_field。

若sortable\_by设置为空集，则所有字段都不可以排序。sortable\_by可以把所有字段（包括非模型表字段）设置为可排序

如设置NameNo设置为可排序：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age')
    sortable_by = ('NameNo',)#设置NameNo字段可排序
```

这时其他字段都不可以排序。

### **22、编辑页面右上角链接（view\_on\_site）**

默认True，使用get\_absolute\_url来显示（若没有则不显示）。若为False，则不会显示。

当然也可以自定义view\_on\_site为callable，这样就可以显示对应返回的url，如下：

```
class StudentAdmin(admin.ModelAdmin):
    list_display = ('NameNo','Sex_color','Age')
    def view_on_site(self, obj):
        return 'http://www.cnblogs.com/watertaro'#在编辑界面右上角显示主页
```

刷新页面编辑界面如下：

![](/files/QbSd7D5j9oEMPd1gQqua)

### **23、按时间搜索（date\_hierarchy）**

只针对date或datetime类型数据，会在search\_fields和Action之间出现一个按照时间搜索的插件

在models.py中增加一张表Books：

```
class Books(models.Model):
    No = models.CharField('编号',max_length = 10)
    Name = models.CharField('书名',max_length = 20)
    CreateTime = models.DateTimeField('创建时间',auto_now_add=True)
    UpdateTime = models.DateTimeField('更新时间',auto_now=True)

    def __str__(self):
        return 'No:' + self.No + ';TeacherName:' + self.Name + ';CreateTime:' + str(self.CreateTime)
```

加完表之后在命令行中执行：

```
python manage.py makemigrations#生成表改动文件
python manage.py migrate#修改表
```

在admin.py中增加如下代码：

```
from djangoTestApp.models import Student,Score,Books#导入Books模型

class BooksAdmin(admin.ModelAdmin):#增加后台操作
    list_display = ('No','Name','CreateTime','UpdateTime',)
    date_hierarchy = 'CreateTime'
    search_fields = ('Name',)

admin.site.register(Books,BooksAdmin)#注册表
```

此时刷新界面进入Bookss可以看到这边多了个如下框中的插件：

![](/files/8fekjOydKVvxPRzYbLx1)

### 24、Django 之 fieldsets

django的admin.py在配置后台编辑页面的时候，如下展示的时候，整个信息都是在一个块里面，这时候如果用到表单分隔，把录入字段凤城几个字段集，这样展示起来就更方便了

![](/files/rd7P13QeWn1pO67gp5ro)

fieldsets就是用来实现这种表格切割的。具体的代码实现如下：

```python
# 表列太多，用 fieldsets,分隔一下，字段少的，使用元组放在一行， <admin.py>
fieldsets = [
    (None, {'fields': [ ('apply_id', 'apply_user', 'apply_city'),('apply_iphone','apply_email','apply_position'),]}),
    ('第一轮面试记录', {'fields':[('first_interview','first_learning_ability','first_professional_competency'),'first_advantage']}),
    ('第二轮面试记录', {'fields': ['two_interview',('two_learning_ability','two_professional_competency',),]}),
    ('HR面试记录', {'fields': [('hr_advantage','hr_disadvantage'),'hr_result','hr_interviewer_user','hr_remark']}),
]
```

![](/files/LkHlB5AhYLXtxGYPCYIw)

### 25、Django 添加列表页自定义按钮

**APP下的 model.py**

```python
from django.db import models
from django.core import validators
from django.utils.html import format_html


class Account(models.Model):
    email = models.EmailField("账户邮箱", unique=True, db_index=True,validators=[validators.EmailValidator('邮箱格式不对！')])
    api_key = models.CharField("账户API_kEY", unique=True, max_length=50)

    class Meta:
        verbose_name = "Cloudflare账户"
        verbose_name_plural = verbose_name
        db_table = "cf_account"

        # 下面是添加的自定义内容，为啥不用button,那是因为还需要写 js, 我比较懒
    def data_update(self):
        button_html = '<a href="#" class="el-button el-button--mini"><i class="el-icon-refresh"></i><span></span>更新数据</a>'
        return format_html(button_html)

    data_update.short_description = '在线更新'
```

**APP下的 admin.py**

```python
''''''
class AccountAdmin(admin.ModelAdmin):
    list_display = ('email', 'api_key','data_update')      # 这里把自定义的 data_update 添加进来
admin.site.register(Account, AccountAdmin)
```

![](/files/StLMBvsMyItI0JM7n0JP)

> 参考： <https://www.cnblogs.com/wanghong1994/p/13666113.html>

### 26、Django添加按钮-actions(集成钉钉权限控制)

```python
pip install DingtalkChatbot
```

例如集成钉钉

setting.py

```python
# 钉钉群的 WEB_HOOK， 用于发送钉钉消息
DINGTALK_WEB_HOOK = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx"
```

dingtalk.py

```python
from dingtalkchatbot.chatbot import DingtalkChatbot
from django.conf import settings


def send(message, at_mobiles=[]):
    # 引用 settings里面配置的钉钉群消息通知的WebHook地址:
    webhook = settings.DINGTALK_WEB_HOOK

    # 初始化机器人小丁, # 方式一：通常初始化方式
    xiaoding = DingtalkChatbot(webhook)

    # 方式二：勾选“加签”选项时使用（v1.5以上新功能）
    # xiaoding = DingtalkChatbot(webhook, secret=secret)

    # Text消息@所有人
    xiaoding.send_text(msg=('面试通知: \n%s' % message), at_mobiles=at_mobiles)
```

admin.py

```python
'''略'''
from .dingtalk import send

class ApplicantAdmin(admin.ModelAdmin):
'''''略'''''
#  ==========================================================
    # 钉钉发送
    def notify_interviewer(self, request, queryset):
        applicant = ""
        first_interviewer_user = ""
        two_interviewer_user = ""
        for obj in queryset:
            applicant = obj.apply_user
            first_interviewer_user = obj.first_interviewer_user.username
            two_interviewer_user = obj.two_interviewer_user.username

        # 这里的消息发送到钉钉， 或者通过 Celery 异步发送到钉钉
        send(
            "候选人: %s\n初始面试官: %s \n复试面试官：%s\n亲爱的面试官，请准备好面试！" % (applicant, first_interviewer_user, two_interviewer_user))
        # send_dingtalk_message.delay("候选人 %s 进入面试环节，亲爱的面试官，请准备好面试： %s" % (candidates, interviewers) )
        # messages.add_message(request, messages.INFO, '已经成功发送面试通知')

    notify_interviewer.short_description = '钉钉通知'
    notify_interviewer.allowed_permissions = ('notify',)       # 设置绑定的权限

    def has_notify_permission(self, request):                  # 判断是有这个权限， 写法： has_权限_permission
        opts = self.opts
        return request.user.has_perm('%s.%s' % (opts.app_label, "notify"))

# ==========================================================
```

model.py

```python
    class Meta:
        verbose_name = '应聘者'
        verbose_name_plural = verbose_name

        permissions = [
            ('notify', 'notify interviewer for candidate review')
        ]
```

![](/files/bqny0VrK0vKWBOpvb2eh)
