0


Django入门教程——用户管理实现

第六章 用户管理实现

教学目的

  • 复习数据的增删改查的实现。
  • 了解数据MD5加密算法以及实现
  • 模型表单中,自定义控件的使用
  • 中间件的原理和使用

需求分析

系统问题

  • 员工档案涉及到员工的秘密,不能让任何人都可以看到,主要是人事部门进行数据的维护,公司领导具有数据的查看权限。
  • 现在我们开发出来的功能,所有人都可以进行访问,都可以进行数据的修改,不符合需求。

系统功能

  • 管理员用户可以进行用户管理,实现用户的添加、修改、删除等
  • 普通用户可以登录系统,修改个人密码等

用户管理相关数据模型

数据模型设计

在这里插入图片描述

添加用户管理相关数据模型

  1. 添加新的应用python manage.py startapp userinfo
  2. 注册新的应用INSTALLED_APPS =['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','archives','userinfo',]
  3. 创建数据模型# 用户信息classUser(models.Model): username = models.CharField(verbose_name='用户账号', max_length=30) password = models.CharField(verbose_name='用户密码', max_length=40) employee = models.ForeignKey(to="archives.Employee", on_delete=models.CASCADE, verbose_name='员工ID', null=True) avatarUrl = models.CharField(verbose_name="头像", max_length=250, null=True, blank=True) role = models.ForeignKey(to="Role", to_field="id", on_delete=models.SET_NULL, verbose_name='角色', null=True) last_login = models.DateTimeField(verbose_name='最后登录时间', auto_now=True) create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)classMeta: db_table ='sys_user'# 角色classRole(models.Model): name = models.CharField(verbose_name='角色名称', max_length=50) remark = models.CharField(verbose_name='备注', max_length=255, null=True, blank=True,)classMeta: db_table ='sys_role'def__str__(self):return self.name
  4. 执行命令创建数据表python manage.py makemigrations python manage.py migrate

用户的增删改查

  1. 用户列表页面user_list.html``````{%extends 'common/base_list.html'%}{% block templet %}<!-- 顶部工具栏模板 --><scripttype="text/html"id="toolbar"><div class="layui-btn-container"><button class="layui-btn layui-btn-sm" lay-event="add"><i class="layui-icon layui-icon-addition"></i> 新增 </button></div></script><!-- 表格操作模板 --><scripttype="text/html"id="TableBar"><div class="layui-clear-space"><a class="layui-btn layui-btn-xs " lay-event="edit"><i class="layui-icon layui-icon-edit"></i> 编辑 </a><a class="layui-btn layui-btn-xs layui-bg-red" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> 删除 </a></div></script>{%endblock%}{% block js %}<script>layui.use(function(){var $ = layui.jquery, form = layui.form, table = layui.table, layer = layui.layer;// 渲染表格 table.render({ elem:'#TableId', url:'/user/list/', method:'post', toolbar:'#toolbar', defaultToolbar:['filter','exports','print'], cols:[[{type:"checkbox", width:50},{field:'index', width:80, title:'序号',align:'center', sort:true},{field:'id', width:80, title:'ID',align:'center', sort:true,hide:true},{field:'username', width:150, title:'用户名',align:'center',sort:true},{field:'employee', width:150, title:'姓名',align:'center',sort:true},{field:'role', width:150, title:'角色',align:'center',sort:true},{field:'last_login', width:150, title:'最近登录',align:'center',sort:true},{title:'操作', minWidth:240, toolbar:'#TableBar', align:"center", fixed:'right'}]], limits:[10,20,50,100,200,500], limit:10, page:true, skin:'row', even:true,});// 头部工具栏事件 table.on('toolbar(TableFilter)',function(obj){if(obj.event ==='add'){ layer.open({ title:['新增','font-size:18px;font-weight:bold;'], type:2, shade:0.3, maxmin:true, shadeClose:true, area:['60%','600px'], content:'/user/add/',});}});});</script>{%endblock%}
  2. 建立视图函数# 用户列表@csrf_exemptdefuser_list(request):if request.method =="GET":return render(request,"userinfo/user_list.html") page = request.POST.get('page',1) limit = request.POST.get('limit',10) searchParams = request.POST.get('searchParams',None) data_obj = User.objects.all() data_page = Paginator(data_obj, limit).page(page) data_list=[] count =(int(page)-1)*int(limit)for row in data_page: count +=1 item_dict ={} field_names =[field.name for field in row._meta.fields]for field in field_names:if field =="employee": item_dict[field]= row.employee.name elif field =="role": item_dict[field]= row.role.name else: item_dict[field]=getattr(row,field) item_dict["index"]=count data_list.append(item_dict)return res_json_data.table_api(data=data_list,count=len(data_obj))
  3. 建立url路由from userinfo import views as user_viewspath("user/list/",user_views.user_list),
  4. 建立用户编辑表单类classedit_form(forms.ModelForm):classMeta: model = models.User fields =['username','role','employee'] widgets ={"employee":forms.Select(attrs={"lay-search":""}),}def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)for name,field in self.fields.items(): field.widget.attrs.update({"class":"layui-input","placeholder":"输入"+field.label})
  5. 建立添加视图函数#settings.pyDEFAULT_PASSWORD ='123'# 设置默认密码``````from django.conf import settings# 用户添加defuser_add(request):if request.method =="GET": form = user_form.edit_form()return render(request,"userinfo/user_edit.html",{"form":form}) form = user_form.edit_form(data=request.POST)if form.is_valid(): form.instance.password = settings.DEFAULT_PASSWORD form.save() messages.success(request,'添加成功')return render(request,"userinfo/user_edit.html",{"form":form})print(form.errors)return render(request,"userinfo/user_edit.html",{"form":form})
  6. 验证用户名不能重复defclean_username(self): username = self.cleaned_data.get("username") user = models.User.objects.filter(username=username).first()if user:raise forms.ValidationError("用户名已存在")return username
  7. 控制员工选择框只能选择没有创建用户的人员def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs) user_obj = models.User.objects.all() user_id_list =[obj.employee_id for obj in user_obj] self.fields['employee'].queryset = Employee.objects.exclude(id__in=user_id_list)for name,field in self.fields.items(): field.widget.attrs.update({"class":"layui-input","placeholder":"输入"+field.label})

对数据库中的密码进行加密

MD5简介

MD5加密算法是一种单向加密算法,是不可逆的一种的加密方式。MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

加密实现

  1. 建立encryption.py文件
  2. 建立md5加密算法函数import hashlibfrom django.conf import settingsdefMD5(str): obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8')) obj.update(str.encode('utf-8'))return obj.hexdigest()
  3. 修改视图函数form.instance.password = MD5(settings.DEFAULT_PASSWORD)

实现密码重置

  1. 表格行操作模板<!-- 表格操作模板 --><scripttype="text/html"id="TableBar"><div class="layui-clear-space"><a class="layui-btn layui-btn-xs " lay-event="reset"><i class="layui-icon layui-icon-edit"></i> 重置密码 </a><a class="layui-btn layui-btn-xs layui-bg-red" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> 删除 </a></div></script>
  2. 建立重置密码视图函数# 重置密码@csrf_exemptdefreset_password(request):id= request.POST.get("id")#用户id password = MD5(settings.DEFAULT_PASSWORD) User.objects.filter(id=id).update(password=password)return res_json_data.success_api()
  3. 通过ajax实现密码重置// 单元格事件table.on('tool(TableFilter)',function(obj){var data = obj.data;//获得当前行数据if(obj.event ==='reset'){ layer.confirm('确认重置为默认密码吗?',{ btn:['确定','取消']//按钮},function(index){ $.post('/user/reset/',{"id":data.id},function(data){if(data.success){ layer.msg(data.msg);}})});}});> jQuery get() 和 post() 方法用于通过 HTTP GET 或 POST 请求从服务器请求数据。> > 语法:> > $.get( URL [, data ] [, callback ] [, dataType ] )> > > > > - URL:发送请求的 URL字符串。> - data:可选的,发送给服务器的字符串或 key/value 键值对(字典)。> - callback:可选的,请求成功后执行的回调函数。> - dataType:可选的,从服务器返回的数据类型。默认:智能猜测(可以是xml, json, script, 或 html)。

用户登录的实现

界面原型

在这里插入图片描述

代码实现

  1. 用户登录路由path("",user_views.user_login)
  2. 登录视图函数# 用户登录defuser_login(request):if request.method =="GET": form = user_form.login_form()return render(request,"userinfo/login.html",{"form":form})
  3. 用户登录页面模板{% load static %}<!DOCTYPEhtml><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>员工信息管理系统</title><linkhref="{%static 'layui/css/layui.css'%}"rel="stylesheet"><style>body{background:url("{% static 'loginbg.png'%}") 0% 0% / cover no-repeat;font-size:12px;}.main-body{top:50%;left:50%;position:absolute;transform:translate(-50%,-50%);overflow:hidden;width: 428px;background-color: #fff;border-radius:12px;}.login-top{height:117px;background-color:#148be4;border-radius:12px 12px 0 0;font-size:30px;font-weight:400;font-stretch:normal;color:#fff;line-height:117px;text-align:center;overflow:hidden;}.login-top .bg1{display:inline-block;width:74px;height:74px;opacity:.1;border-radius:0 74px 0 0;position:absolute;left:0;top:43px;background-color: #fff;}.login-top .bg2{display:inline-block;width:94px;height:94px;opacity:.1;border-radius:50%;position:absolute;right:-16px;top:-16px;background-color: #fff;}.center{width:288px;margin:0 auto;padding-top:40px;padding-bottom:15px;position:relative;}.login-btn{width:288px;height:40px;background-color:#1E9FFF;border-radius:16px;margin:24px auto 0;text-align:center;line-height:40px;color:#fff;font-size:14px;letter-spacing:0;cursor:pointer;border:none;}.center{width:288px;margin:0 auto;padding-top:40px;padding-bottom:15px;position:relative;}</style></head><body><divclass="main-body"><divclass="login-top"><span>员工信息管理系统</span><spanclass="bg1"></span><spanclass="bg2"></span></div></div><scriptsrc="{%static 'layui/layui.js'%}"></script><script>layui.use(function(){var $ = layui.jquery;var layer = layui.layer;{%for msg in messages %} layer.alert('{{ msg}}');{% endfor %}});</script></body></html>> 绝对定位布局(position)> > > 1. 定位方式属性 - static 默认,元素在文档常规流中当前的布局位置- relative :不会脱离文档流,不会浮起来,一般为里面的absolute 元素提供定位依据- absolute 元素会被移出正常文档流,相对于上一个绝对定位的父元素来进行定位- fixed 元素会被移出正常文档流,相对于屏幕视口(viewport)的位置来指定元素位置> 2. absolute相对定位详解 - 父元素没有设置相对定位或绝对定位的情况下,元素相对于根元素定位(即html元素)- 父元素设置了相对定位或绝对定位,元素会相对于离自己最近的设置了相对或绝对定位的父元素进行定位> 3. 定位属性 - top样式属性定义了定位元素的上外边距边界与其包含块上边界之间的偏移- bottom 定位元素下外边距边界与其包含块下边界之间的偏移- left 定位元素的上外边距边界与其包含块上边界之间的偏移- right 定位元素的右外边距边界与其包含块右边界之间的偏移- transform: translate(12px, 50%); 水平平移,第一个参数对应X轴,第二个参数对应Y轴。如果第二个参数未提供,则默认值为0,注意参数用逗号分隔
  4. 用户登录表单类# 登录表单类classlogin_form(forms.ModelForm):classMeta: model =models.User fields =['username','password'] widgets ={'password':forms.PasswordInput(attrs={"lay-affix":"eye"},render_value=True),}defclean_password(self): password = self.cleaned_data.get("password")return MD5(password)def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)for name,field in self.fields.items(): field.widget.attrs.update({"class":"layui-input","placeholder":"输入"+field.label})> > - render_value=True ——保持上次输入的值
  5. 修改视图函数,进行用户登录验证# 用户登录defuser_login(request):if request.method =="GET": form = user_form.login_form()return render(request,"userinfo/login.html",{"form":form}) form = user_form.login_form(data=request.POST)if form.is_valid():print(form.cleaned_data,"===校验完成")#打印form提交的所有数据 user_obj = User.objects.filter(**form.cleaned_data).first()ifnot user_obj: messages.warning(request,'用户名或密码错误')return render(request,"userinfo/login.html",{"form":form})# 登录成功return redirect("/employee/list/")print(form.errors)return render(request,"userinfo/login.html",{"form":form})

是否登录检验

会话Session

  1. 简介Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。
  2. 操作语法> > - 设置session,通过request.session字典request.session['user_info']={'id':user_obj.id,'user_id':user_obj.id_number,'user_name':user_obj.user_name,'role_id':user_obj.role_id,}> - session有效期设置request.session.set_expiry(value)- 如果value是个整数,session会在设置秒数后失效。- 如果value是个datatimetimedelta,session就会在这个时间后失效。- 如果value是0,用户关闭浏览器session就会失效。//我们用的就是这种方式- 如果value是None,session会依赖全局session失效策略。> - 获取session值后端:user_info = request.session.get('user_info')前端:request.session.user_info.name

修改代码实现访问授权

  1. 通过session记录登录用户信息# 登录成功request.session["user_info"]={"id":user_obj.id,"username":user_obj.username,"name":user_obj.employee.name,}request.session.set_expiry(0)return redirect("/employee/list/")
  2. 用户登录状态验证user_info = request.session.get("user_info")print(user_info,"==用户信息")ifnot user_info:return redirect("/")

中间件

中间件在Django中是一种轻量级、底层的“插件”系统,用于全局地处理请求和响应。它位于Django的请求和响应处理过程之间,可以对HTTP请求和响应进行预处理和后处理,从而实现诸如权限控制、日志记录、数据压缩、缓存等功能。

中间件的请求流程:

在这里插入图片描述

用中间件进行登录验证拦截

  1. 建立auth.py文件,创建中间件类from django.utils.deprecation import MiddlewareMixinfrom django.shortcuts import redirectfrom datetime import datetimeclassAuthMiddleware(MiddlewareMixin):defprocess_request(self, request):print("===访问地址:",request.path,datetime.now()) user_info = request.session.get('user_info')print(user_info,"==登陆用户信息")if user_info:returnreturn redirect("/")
  2. 在setting中注册中间件MIDDLEWARE =['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','userinfo.auth.AuthMiddleware',]- 第9行:注册中间件
  3. 处理302错误,重定向错误classAuthMiddleware(MiddlewareMixin):defprocess_request(self, request):print("===访问地址:",request.path,datetime.now()) pass_urls =['/']if request.path in pass_urls:return user_info = request.session.get('user_info')print(user_info,"==登陆用户信息")if user_info:returnreturn redirect("/")- return 没有返回值,将进行放行,否则将进行拦截

注销和密码修改

注销操作

  1. 修改公共模板页面添加用户信息和菜单。<liclass="layui-nav-item"style="float: right;"><ahref="javascript:void(0);"><imgsrc="https://unpkg.com/[email protected]/demo/avatar/1.jpg"class="layui-nav-img"> {{request.session.user_info.name}} </a><dlclass="layui-nav-child"><dd><ahref="">修改密码</a></dd><dd><ahref="/user/logout/">退出</a></dd></dl></li>
  2. 添加注销视图函数# 用户退出defuser_logout(request): request.session.clear()return redirect("/")

密码修改

  1. 创建单行编辑模版页面single_edit_dlg.html``````{%extends 'common/layout_dlg.html'%}{% block css %}<style>.layui-input-block{margin-left: 150px;}.layui-form-label{width: 120px;}</style>{%endblock%}{%block content%}<divclass="layui-card-body"><formclass="layui-form"method="post"novalidate> {% csrf_token %} {% for field in form %} <divclass="layui-form-item"> {% if field.field.required %} <labelclass="layui-form-label label-required-next">{{ field.label }}:</label> {% else %} <labelclass="layui-form-label">{{ field.label }}:</label> {% endif %} <divclass="layui-input-block"> {{ field }} <spanstyle="color: red">{{ field.errors.0 }}</span></div></div> {% endfor %} <divclass="layui-form-item"><divclass="layui-input-block"><buttontype="submit"class="layui-btn"lay-submit>确认提交</button></div></div></form></div>{% endblock %}{%block js%}{% block extendsjs %}{% endblock %}{% for msg in messages %}<script> layui.use(['layer'],function(){var iconValue ="{{msg.tags}}"=='success'?1:2; layer.msg('{{msg}}',{ icon: iconValue, time:2000},function(){if("{{msg.tags}}"=='success'){ parent.layer.close(parent.layer.getFrameIndex(window.name));//关闭当前页 parent.layui.table.reload('TableId');//重新加载父窗口表格}})})</script>{% endfor %}{% endblock %}
  2. 创建密码修改表单类# 密码修改表单类classpassword_form(forms.ModelForm): confirm_password = forms.CharField( label="确认新密码", required=True, widget=forms.PasswordInput(render_value=True,attrs={"lay-affix":"eye"})) new_password = forms.CharField( label="新密码", required=True, widget=forms.PasswordInput(render_value=True,attrs={"lay-affix":"eye"}))classMeta: model =models.User fields =['username','password','new_password','confirm_password'] widgets ={'password':forms.PasswordInput(attrs={"lay-affix":"eye"},render_value=True),}def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)for name,field in self.fields.items(): field.widget.attrs.update({"class":"layui-input","placeholder":"输入"+field.label})
  3. 完善密码修改视图函数# 修改密码defchange_password(request):if request.method =="GET": form = user_form.password_form()return render(request,"common/single_edit_dlg.html",{"form":form}) user_info = request.session['user_info'] user_id = user_info['id'] row_obj = User.objects.filter(id=user_id).first() form = user_form.password_form(data=request.POST)if form.is_valid(): username = form.cleaned_data['username'] password = MD5(form.cleaned_data['password'])if row_obj.username != username or row_obj.password!=password: messages.error(request,'用户名或密码不正确')return render(request,"common/single_edit_dlg.html",{"form":form})if form.cleaned_data['new_password']!= form.cleaned_data['confirm_password']: messages.error(request,'两次密码输入不一致')return render(request,"common/single_edit_dlg.html",{"form":form}) new_password = MD5(form.cleaned_data['new_password']) User.objects.filter(id=user_id).update(password=new_password) messages.success(request,'修改成功')return render(request,"common/single_edit_dlg.html",{"form":form})return render(request,"common/single_edit_dlg.html",{"form":form})

‘password’])
if row_obj.username != username or row_obj.password!=password:
messages.error(request, ‘用户名或密码不正确’)
return render(request,“common/single_edit_dlg.html”,{“form”:form})
if form.cleaned_data[‘new_password’]!= form.cleaned_data[‘confirm_password’]:
messages.error(request, ‘两次密码输入不一致’)
return render(request,“common/single_edit_dlg.html”,{“form”:form})
new_password = MD5(form.cleaned_data[‘new_password’])
User.objects.filter(id=user_id).update(password=new_password)
messages.success(request, ‘修改成功’)
return render(request,“common/single_edit_dlg.html”,{“form”:form})

   return render(request,"common/single_edit_dlg.html",{"form":form})
标签: django sqlite 数据库

本文转载自: https://blog.csdn.net/ffei060828/article/details/143279785
版权归原作者 无忧无虑Coding 所有, 如有侵权,请联系我们删除。

“Django入门教程——用户管理实现”的评论:

还没有评论