1. 数据库新建库-app[models.py]
from django.db import models
class Admin(models.Model):
    """管理员表"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)
2. 执行命令生成数据库表
# 在mysql中生成表
    '''
    1. 工具连接mysql生成数据库 
        create database 库名 default charset utf8 collate utf8_general_ci;
    
    2. django 中修改配置文件,连接Mysql
    
    3. django命令生成数据库表
        python manage.py makemigrations
        python manage.py migrate
    '''
3. 创建url,链接视图函数,项目[url.py]
# 管理员管理
    path('admin/list/', admin.admin_list),
    path('admin/add/', admin.admin_add),
    path('admin/<int:nid>/update/', admin.admin_update),
    path('admin/<int:nid>/delete/', admin.admin_delete),
    path('admin/<int:nid>/reset/', admin.admin_reset),
4. 创建md5加密方法app[utils][encrypt.py]
from bbc_auto import settings
# setting中有默认的随机生成的言
import hashlib
def md5(data_string):
    # salt = "xxxxx"  # 因为加密方式是固定的,所以加个言
    # obj = hashlib.md5(salt.encode("utf-8"))
    obj = hashlib.md5(settings.SECRET_KEY.encode("utf-8"))
    obj.update(data_string.encode("utf-8"))
    return obj.hexdigest()
5. 创建视图函数.app[views][admin.py]
# 模块导入,先写内置-第三方-自定义
from django.shortcuts import render, redirect
from django.core.exceptions import ValidationError
from app01 import models
from app01.utils.pagemtion import Pagination
from app01.utils.encrypt import md5
def admin_list(request):
    """管理员列表"""
    # 构造搜索
    data_dict = {}
    search_data = request.GET.get("q", "")  # 有值的话拿值,没值空字符串
    if search_data:
        data_dict["username__contains"] = search_data
    # 根据搜索条件去数据库获取
    querty = models.Admin.objects.filter(**data_dict)
    # 分页
    page_object = Pagination(request, querty)
    context = {
        "querty": page_object.page_queryset,
        "page_string": page_object.html(),
        "search_data": search_data
    }
    return render(request, "admin_list.html", context)
from app01.utils.bootstrap import BootStrapModelForm
from django import forms
class AdminModelForm(BootStrapModelForm):
    # 添加一个确认密码的输入框,这个字段在数据库中是没有的
    confirm_password = forms.CharField(label="确认密码",
                                       # render_value=True:点击确认后不清空密码
                                       widget=forms.PasswordInput(render_value=True),  # render_value=True 定义密码保密显示
                                       )
    class Meta:
        model = models.Admin
        fields = ["username", "password", "confirm_password"]
        widgets = {
            "password": forms.PasswordInput(render_value=True)
        }
    def clean_password(self):  # 获取密码加密
        pwd = self.cleaned_data.get("password")
        return md5(pwd)
    def clean_confirm_password(self):  # 钩子方法: 获取密码和确认密码
        # print(self.cleaned_data)  # (self.cleaned_data)  # 验证通过后,里面所有的内容
        pwd = self.cleaned_data.get("password")  # 此时获取的pwd就是加完秘的
        confirm = md5(self.cleaned_data.get("confirm_password"))
        if confirm != pwd:
            raise ValidationError("密码不一致")
        return confirm  # return 返回的什么保存到数据库的值就是什么
def admin_add(request):
    """添加管理员"""
    title = "新建管理员"
    if request.method == "GET":
        form = AdminModelForm()
        return render(request, "change.html", {"form": form, "title": title})
    form = AdminModelForm(data=request.POST)
    if form.is_valid():
        # {'username': 'admin', 'password': '123', 'confirm_password': '321'}
        # print(form.cleaned_data)  # 验证通过后,里面所有的内容
        form.save()
        return redirect("/admin/list/")
    return render(request, "change.html", {"form": form, "title": title})  # 如果有错误的话会自动效验
class AdminUpdate(BootStrapModelForm):
    class Meta:
        model = models.Admin
        fields = ["username"]
def admin_update(request, nid):
    """编辑"""
    # 判断路径中的nid是否正确  对象 / none
    row_object = models.Admin.objects.filter(id=nid).first()
    if not row_object:
        # 方式一: 写一个提示错误的页面
        # return render(request, 'error.html', {"msg": "数据不存在"})
        # 方式二: 跳转回首页
        return redirect('/admin/list/')
    title = "编辑管理员"
    if request.method == "GET":
        form = AdminUpdate(instance=row_object)  # instance=row_object:显示默认值
        return render(request, "change.html", {"form": form, "title": title})  # 如果有错误的话会自动效验
    form = AdminUpdate(data=request.POST, instance=row_object)
    if form.is_valid():
        form.save()
        return redirect('/admin/list/')
    return render(request, "change.html", {"form": form, "title": title})  # 如果有错误的话会自动效验
def admin_delete(request, nid):
    """删除"""
    models.Admin.objects.filter(id=nid).delete()
    return redirect('/admin/list/')
class AdminReset(BootStrapModelForm):
    # 添加一个确认密码的输入框,这个字段在数据库中是没有的
    confirm_password = forms.CharField(label="确认密码",
                                       # render_value=True:点击确认后不清空密码
                                       widget=forms.PasswordInput(render_value=True),  # 定义密码保密显示
                                       )
    class Meta:
        model = models.Admin
        fields = ["password", "confirm_password"]
        widgets = {
            "password": forms.PasswordInput(render_value=True)
        }
    def clean_password(self):  # 获取密码加密
        pwd = self.cleaned_data.get("password")
        md5_pwd = md5(pwd)
        # 去数据库效验当前密码和新输入的密码是否一致
        # self.instance就是下面代码中传入的对象 .pk:就是路径中的id
        exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
        print(exists)
        if exists:
            raise ValidationError("密码不能与之前相同")
        return md5_pwd
    def clean_confirm_password(self):  # 钩子方法: 获取密码和确认密码
        # print(self.cleaned_data)  # (self.cleaned_data)  # 验证通过后,里面所有的内容
        pwd = self.cleaned_data.get("password")  # 此时获取的pwd就是加完秘的
        confirm = md5(self.cleaned_data.get("confirm_password"))
        from django.core.exceptions import ValidationError
        if confirm != pwd:
            raise ValidationError("密码不一致")
        return confirm  # return 返回的什么保存到数据库的值就是什么
def admin_reset(request, nid):
    """重置密码"""
    row_object = models.Admin.objects.filter(id=nid).first()
    if not row_object:
        return redirect('/admin/list/')
    title = "重置密码-{}".format(row_object.username)
    if request.method == "GET":
        form = AdminReset()
        return render(request, "change.html", {"form": form, "title": title})  # 如果有错误的话会自动效验
    form = AdminReset(data=request.POST, instance=row_object)
    if form.is_valid():
        form.save()
        return redirect('/admin/list/')
    return render(request, "change.html", {"form": form, "title": title})  # 如果有错误的话会自动效验
6. 创建列表html,app[templates][admin_list.html]
{% extends 'one.html'%}
{% block content %}
<div class="container">
    <div style="margin-bottom:10px;" class="clearfix">
        <a class="btn btn-success" href="/admin/add/">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
            新建管理员</a>
        <div style="float:right;width:300px;">
            <form method="get">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="关键字"
                           value="{{ search_data }}">
                    <span class="input-group-btn">
                    <button class="btn btn-default" type="submit">
                        <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                    </button>
                  </span>
                </div>
            </form>
        </div>
        <a class="btn btn-success" href="/phone/add/">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
            新建手机号ModelForm</a>
    </div>
    <div class="panel panel-default">
        <!-- Default panel contents -->
        <div class="panel-heading">
            <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
            管理员列表
        </div>
        <!-- Table -->
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>密码</th>
                <th>重置密码</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for obj in querty %}
            <tr>
                <th>{{ obj.id }}</th>
                <th>{{ obj.username }}</th>
                <th>*******</th>
                <td>
                    <a href="/admin/{{ obj.id }}/reset/">重置密码</a>
                </td>
                <td>
                    <a class="btn btn-primary btn-xs" href="/admin/{{obj.id}}/update/">编辑</a>
                    <a class="btn btn-danger btn-xs" href="/admin/{{obj.id}}/delete/">删除</a>
                </td>
            </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
    <ul class="pagination">
        {{ page_string }}
    </ul>
</div>
{% endblock %}
7. 创建添加html,app[templates][change.html]
{% extends 'one.html' %}
{% block content %}
<div class="container">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">{{ title }}</h3>
        </div>
        <div class="panel-body">
            <!--            novalidate: 关掉浏览器的校验-->
            <form method="post" novalidate>
                {% csrf_token %}
                {% for field in form %}
                <div class="form-group">
                    <label>{{ field.label }}</label>
                    <!--                    <input type="text" class="form-control" placeholder="姓名" name="user">-->
                    {{ field }}
                    <span style="color:red;"> {{ field.errors.0 }}</span>
                </div>
                {% endfor %}
                <button type="submit" class="btn btn-primary">提 交</button>
            </form>
        </div>
    </div>
</div>
{% endblock %}
8. 创建修改html,app[templates][change.html],添加和修改页面一样,使用同一个页面即可
9. 删除可直接根据nid删除,不需要html页面
10 . 重置密码页面也一样,可以复用app[templates][change.html]