管理员管理
创建数据库表
models.py
class Admin(models.Model): """管理员表""" username = models.CharField(verbose_name="用户名", max_length=32) password = models.CharField(verbose_name="密码", max_length=64)
在数据库生成
Tools->run manage.py task
执行命令
makemigrations migrate
数据库中插入一条数据
insert into app01_admin(username,password) values("coco", "123");
增加管理员菜单
修改/app01/templates/layout.html
<ul class="nav navbar-nav">
<li><a href="/admin/list/">管理员账户管理</a></li>
<li><a href="/depart/list/">部门管理</a></li>
<li><a href="/user/list/">用户管理</a></li>
<li><a href="/prettynum/list/">靓号管理</a></li>
</ul>
在views文件夹下新建admin.py,用于存放管理账户管理的视图函数
修改urls.py
#导入admin from app01.views import depart, pretty, user, admin #添加url urlpatterns = [ #管理员账户管理 path('admin/list/', admin.admin_list), ]
admin.py
from django.shortcuts import render
from app01 import models
def admin_list(request):
"""管理员列表"""
queryset = models.Admin.objects.all()
context = {
'queryset' : queryset
}
return render(request, 'admin_list.html', context)
在templates文件夹创建admin_list.html
{% extends 'layout.html' %} {% block content %} <div class="container"> <div style="margin-bottom: 10px" class="clearfix"> <a class="btn btn-success" href="#"> <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 新建管理员 </a> <div style="float: right; width: 300px;"> <form> <div class="input-group"> <input type="text" name="q" class="form-control" placeholder="Search for..." 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><!-- /input-group --> </form> </div> </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> </tr> </thead> <tbody> {% for obj in queryset %} <tr> <th>{{ obj.id }}</th> <td>{{ obj.username }}</td> <td>************</td> <td> <a class="btn btn-primary btn-xs" href="#">编辑</a> <a class="btn btn-danger btn-xs" href="#">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> {% endblock %}
管理员列表就可以在前端展示出来了
管理员列表添加分页
admin.py
from django.shortcuts import render from app01 import models from app01.utils.pagination import Pagination def admin_list(request): """管理员列表""" queryset = models.Admin.objects.all() page_object = Pagination(request, queryset) context = { 'queryset' : page_object.page_queryset, 'page_string': page_object.html() } return render(request, 'admin_list.html', context)
admin_list.html
{% extends 'layout.html' %} {% block content %} <div class="container"> <div style="margin-bottom: 10px" class="clearfix"> <a class="btn btn-success" href="#"> <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 新建管理员 </a> <div style="float: right; width: 300px;"> <form> <div class="input-group"> <input type="text" name="q" class="form-control" placeholder="Search for..." 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><!-- /input-group --> </form> </div> </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> </tr> </thead> <tbody> {% for obj in queryset %} <tr> <th>{{ obj.id }}</th> <td>{{ obj.username }}</td> <td>************</td> <td> <a class="btn btn-primary btn-xs" href="#">编辑</a> <a class="btn btn-danger btn-xs" href="#">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> <ul class="pagination"> {{ page_string }} </ul> </div> {% endblock %}
完成
添加搜索功能
admin.py
from django.shortcuts import render from app01 import models from app01.utils.pagination import Pagination def admin_list(request): """管理员列表""" #构造搜索 data_dict = {} search_data = request.GET.get('q', "") if search_data: data_dict[ "username__contains"] = search_data #根据搜索条件去数据库获取 queryset = models.Admin.objects.filter(**data_dict) #分页 page_object = Pagination(request, queryset) context = { 'queryset' : page_object.page_queryset, 'page_string': page_object.html(), "search_data": search_data, } return render(request, 'admin_list.html', context)
admin_list.html
新建管理员
admin_list.html
<a class="btn btn-success" href="/admin/add/"> <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 新建管理员 </a>
urls.py
path('admin/add/', admin.admin_add),
修改/app01/views/admin.py
from django import forms from app01.utils.bootstrap import BootStrapModelForm class AdminModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput ) class Meta: model = models.Admin fields = ["username", "password", "confirm_password"] widgets = { "password": forms.PasswordInput } def admin_add(request): """添加管理员""" form = AdminModelForm() return render(request, 'change.html', {'form': form, "title": "新建管理员"})
按照之前的套路,我应该会新建一个名为admin_add.html的HTML文件来展示添加界面
这次我们优化一下
不管是pretty_add.html或者user_add.html,除了标题不一样,其他的都是一样的
没有必要在创建一个单独的HTML页面,我们只需要在一个公共的HTML页面中传入各自的标题即可
新建zpp01/templates/change.html
{% extends 'layout.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> {{ field }} {# {{ field.errors }}错误信息是一个列表[错误1,错误2,错误3...], {{ field.errors.0 }}只取第一个错误1 #} <span style="color: red;">{{ field.errors.0 }}</span> {# <input type="text" class="form-control" placeholder="姓名" name="user"> #} </div> {% endfor %} <button type="submit" class="btn btn-primary">提 交</button> </form> </div> </div> </div> {% endblock %}
浏览器测试
新建管理员页面点击提交,将数据保存到数据库
admin.py
from django import forms from app01.utils.bootstrap import BootStrapModelForm class AdminModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput ) class Meta: model = models.Admin fields = ["username", "password", "confirm_password"] widgets = { "password": forms.PasswordInput } 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(): form.save() return redirect('/admin/list/') return render(request, 'change.html', {'form': form, "title": title})
存在问题:
密码跟确认密码输入不一致也能提交成功,需要添加校验,使密码、确认密码输入一致
修改app01/views/admin.py
,增加钩子函数 clean_confirm_password
#包的导入要按照内置包、第三方包、自己写的这种顺序导入,短的在前面
from django import forms
#导入异常包 from django.core.exceptions import ValidationError from app01.utils.bootstrap import BootStrapModelForm class AdminModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput ) class Meta: model = models.Admin fields = ["username", "password", "confirm_password"] widgets = { "password": forms.PasswordInput } #钩子函数 def clean_confirm_password(self): password = self.cleaned_data.get("password") confirm = self.cleaned_data.get("confirm_password") if confirm != password: raise ValidationError("密码不一致,请重新输入。")
#返回什么,此字段以后保存到数据库就是什么
return confirm
可以发现,数据校验成功了
但是还有个问题,当我们点击保存后,密码和密码确认框中的数据清空了
这样不是太友好,因此我们需要添加一个属性
render_value=True
浏览器测试,这样密码就不会清空了
现在又出现一个问题
直接将密码明文存储进数据库,很不安全
我们最好对其进行加密后,再进行保存
密码采用md5加密
新建app01/utils/encrypt.py
文件
import hashlib from django.conf import settings def md5(data_string): obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8')) obj.update(data_string.encode('utf-8')) return obj.hexdigest()
修改app01/views/admin.py
from django import forms from django.core.exceptions import ValidationError from app01.utils.bootstrap import BootStrapModelForm from app01.utils.encrypt import md5 class AdminModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput(render_value=True) ) class Meta: model = models.Admin fields = ["username", "password", "confirm_password"] widgets = { "password": forms.PasswordInput(render_value=True) } # clean_字段名 def clean_password(self): pwd = self.cleaned_data.get("password") # return什么.password字段保存什么 return md5(pwd) #钩子函数 def clean_confirm_password(self): pwd = self.cleaned_data.get("password") confirm = md5(self.cleaned_data.get("confirm_password")) if confirm != pwd: raise ValidationError("密码不一致,请重新输入。") #返回什么,此字段以后保存到数据库就是什么 return confirm
看看效果吧
添加管理员编辑页面
修改app01/templates/admin_list.html
<td>
<a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="#">删除</a>
</td>
修改myproject/myproject/urls.py
path('admin/<int:nid>/edit/', admin.admin_edit),
添加一个公共的错误信息提示页面
在myprojrct/app01/templates/ 新建 error.html
error.html
{% extends 'layout.html' %} {% block content %} <div class="container"> <div class="alert alert-danger" role="alert">{{ msg }}</div> </div> {% endblock %}
编写视图函数
修改myproject/app01/views/admin.py
class AdminEditModelForm(BootStrapModelForm): class Meta: model = models.Admin fields = ["username"] def admin_edit(request,nid): """编辑管理员""" #如果数据存在返回一个对象,如果数据不存在,返回none row_object = models.Admin.objects.filter(id=nid).first() #判断nid是否存在 if not row_object: return render(request,'error.html', {"msg": "数据不存在"}) title = "编辑管理员" if request.method == "GET": # instance = row_object显示编辑框的默认值 form = AdminEditModelForm(instance=row_object) return render(request, 'change.html', {"form": form, "title": title}) form = AdminEditModelForm(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})
浏览器访问,修改coco
为coco1
点击提交
添加管理员删除
修改app01/templates/admin_list.html
<td> <a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a> <a class="btn btn-danger btn-xs" href="/admin/{{ obj.id}}/delete">删除</a> </td>
修改myproject/myproject/urls.py
path('admin/<int:nid>/delete/', admin.admin_delete),
修改myproject/app01/views/admin.py
def admin_delete(request,nid): """删除管理员""" models.Admin.objects.filter(id=nid).delete() return redirect('/admin/list/')
删除coco1
完成
管理员重置密码
修改app01/templates/admin_list.html
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>密码</th>
<th>重置密码</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.username }}</td>
<td>************</td>
<td>
<a href="/admin/{{ obj.id }}/reset/">重置密码</a>
</td>
<td>
<a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/admin/{{ obj.id }}/delete">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
修改myproject/myproject/urls.py
path('admin/<int:nid>/reset/', admin.admin_reset),
修改myproject/app01/views/admin.py
class AdminResetModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput(render_value=True) ) class Meta: model = models.Admin fields = ["password", "confirm_password"] widgets = { "password": forms.PasswordInput(render_value=True) } # clean_字段名 def clean_password(self): pwd = self.cleaned_data.get("password") # return什么.password字段保存什么 return md5(pwd) #钩子函数 def clean_confirm_password(self): pwd = self.cleaned_data.get("password") confirm = md5(self.cleaned_data.get("confirm_password")) if confirm != pwd: raise ValidationError("密码不一致,请重新输入。") #返回什么,此字段以后保存到数据库就是什么 return confirm def admin_reset(request,nid): """重置密码""" row_object = models.Admin.objects.filter(id=nid).first() if not row_object: return render('/admin/list/') title = "重置密码 - {}".format(row_object.username) if request.method == "GET": form = AdminResetModelForm() return render(request, 'change.html', {"form": form, "title": title}) form = AdminResetModelForm(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})
添加功能:重置密码时不允许跟之前设置的密码一致
修改myproject/app01/views/admin.py
class AdminResetModelForm(BootStrapModelForm): confirm_password = forms.CharField( label="确认密码", #默认生成的input框为text框,想要密码不显示需要使用passwordInput框,定义widget插件实现 widget=forms.PasswordInput(render_value=True) ) class Meta: model = models.Admin fields = ["password", "confirm_password"] widgets = { "password": forms.PasswordInput(render_value=True) } # clean_字段名 def clean_password(self): pwd = self.cleaned_data.get("password") md5_pwd = md5(pwd) #去数据库校验当前密码和新重置的密码是否一致 exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists() if exists: raise ValidationError("不能与以前的密码相同") # return什么.password字段保存什么 return md5_pwd #钩子函数 def clean_confirm_password(self): pwd = self.cleaned_data.get("password") confirm = md5(self.cleaned_data.get("confirm_password")) if confirm != pwd: raise ValidationError("密码不一致,请重新输入。") #返回什么,此字段以后保存到数据库就是什么 return confirm
完成