用户登录验证+url别名反推
一、用户登录验证
- 验证两次密码输入是否一致
- 自定制密码验证规则(必须包含字母、数字和特殊字符)
- 验证码的使用
- 免登录期限
views.py
1 from django.http import HttpResponse 2 from django.shortcuts import render 3 from django.urls import reverse 4 from io import BytesIO 5 from django.forms import fields 6 from django import forms 7 from django.core.exceptions import ValidationError,NON_FIELD_ERRORS # NON_FIELD_ERRORS == __all__ 8 import json 9 10 from utils.check_code import create_validate_code 11 12 def index_get(request,**kwargs): 13 """ 14 无用,测试通过url别名反推url 15 :param request: 16 :param kwargs: 17 :return: 18 """ 19 print(kwargs) 20 current_path = reverse("index_all",kwargs=kwargs) 21 # print(current_path) 22 return HttpResponse("nihao") 23 24 class Login(forms.Form): 25 """ 26 form组件验证用户输入 27 """ 28 user = fields.CharField( 29 max_length=32, 30 error_messages={ 31 "required":"用户名不能为空" 32 } 33 ) 34 pwd = fields.RegexField( 35 '^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%\^\&\*\(\)])[0-9a-zA-Z!@#$\%\^\&\*\(\)]{8,32}', 36 min_length=8, 37 max_length=32, 38 error_messages={ 39 "required":"密码不能为空", 40 "invalid":"密码必须包含数字字符串和特殊字符", 41 "min_length":"密码长度不得小于8位", 42 "max_length":"密码长度不得大于32位", 43 } 44 ) 45 #再次输入的密码只是为了验证一致性,可以不自定制匹配 46 pwd_again = fields.RegexField( 47 '^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\%\^\&\*\(\)])[0-9a-zA-Z!@#$\%\^\&\*\(\)]{8,32}', 48 min_length=8, 49 max_length=32, 50 error_messages={ 51 "required":"密码不能为空", 52 "invalid":"密码必须包含数字字符串和特殊字符", 53 "min_length":"密码长度不得小于8位", 54 "max_length":"密码长度不得大于32位", 55 } 56 ) 57 check_code = fields.CharField() 58 def clean(self): 59 # self.cleaned_data["pwd"] 报错 60 a = self.cleaned_data.get("pwd") 61 b = self.cleaned_data.get("pwd_again") 62 if a == b: 63 pass 64 else: 65 raise ValidationError("密码不一致") 66 67 # Create your views here. 68 def index(request): 69 if request.method == "GET": 70 return render(request, "index.html") 71 else: 72 msg = {"status":True,"error":None,"check_code":None} 73 # print(request.POST,request.session.get("code")) 74 login_test = Login(request.POST) 75 if login_test.is_valid(): 76 request.session["user"] = login_test.cleaned_data.get("user") 77 if request.POST.get("box"): 78 # 设置免登录,不完全 79 request.session.set_expiry(60 * 60 * 24 * 3) # 设置session的生命周期,单位为秒 80 # print(login_test.errors.get("__all__")) 81 if (request.session.get("code")).lower() == (login_test.cleaned_data.get("check_code")).lower(): 82 msg["check_code"] = True 83 else: 84 # 不管通过不通过,验证码都应该被验证,但放在is_valid外面又无法获取用户输入的验证码 85 if (request.session.get("code")).lower() == (login_test.cleaned_data.get("check_code")).lower(): 86 msg["check_code"] = True 87 msg["status"] = False 88 msg["error"] = login_test.errors 89 return HttpResponse(json.dumps(msg)) 90 91 def create_checkcode(request): 92 img,code = create_validate_code() 93 f = BytesIO() # 获取一块内存空间 94 img.save(f,'PNG') # 将验证码生成函数发送来的图片保存在这块空间中,img是一个对象 95 # print(code) 96 # print(request.session.keys()) 97 request.session["code"] = code # 将验证码字符串保存在session中以供验证输入时使用 98 request.session.set_expiry(20) # 验证码20秒后失效 99 # return render(request,"login.html",{"img":f.getvalue()}) # 乱码 100 return HttpResponse(f.getvalue()) # 获取把保存在这块内存中的数据 101 102 def log_success(request): 103 """ 104 用户登陆成功返回欢迎页面,显示用户名 105 :param request: 106 :return: 107 """ 108 print(request.session.get("user")) 109 return render(request,"log_success.html",{"user":request.session.get("user")})
index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> 7 <style> 8 </style> 9 </head> 10 <body> 11 12 <div style="width: 500px;background-color: #2aabd2;height: 400px;margin: 10px auto"> 13 <form class="form-horizontal" action="/index/" method="post" id="fr"> 14 {% csrf_token %} 15 <div class="form-group ipu"> 16 <label for="inputEmail3" class="col-sm-2 control-label">用户名</label> 17 <div class="col-sm-10"> 18 <input type="text" placeholder="用户名" name="user"> 19 <span id="user"></span> 20 </div> 21 </div> 22 <div class="form-group ipu"> 23 <label for="inputPassword3" class="col-sm-2 control-label">密码</label> 24 <div class="col-sm-10"> 25 <input type="password" placeholder="密码" name="pwd"> 26 <span id="pwd"></span> 27 </div> 28 </div> 29 <div class="form-group ipu"> 30 <label for="inputPassword3" class="col-sm-2 control-label">再次输入</label> 31 <div class="col-sm-10"> 32 <input type="password" placeholder="密码" name="pwd_again"> 33 <span id="pwd_again"></span> 34 </div> 35 </div> 36 <div class="form-group ipu"> 37 <label for="inputPassword3" class="col-sm-2 control-label">验证码</label> 38 <div class="col-sm-10"> 39 <input type="text" placeholder="验证码" name="check_code"> 40 <img src="../create_checkcode" alt="" onclick="img(this)"> 41 <span id = "check_code"></span> 42 </div> 43 </div> 44 <div class="form-group ipu"> 45 <div class="col-sm-10"> 46 <input type="checkbox" value="1" name="box"> 47 <span>三天内免登录</span> 48 </div> 49 </div> 50 51 </form> 52 <button type="button" class="btn btn-primary" onclick="sub()" style="margin: 10px 100px">登录</button> 53 </div> 54 55 <script src="/static/jquery-3.1.1.js"></script> 56 <script src="/static/bootstrap/js/bootstrap.js"></script> 57 <script> 58 function sub() { 59 $.ajax({ 60 url:'/index/', 61 data:$("#fr").serialize(), //取出form表单中的所有用户输入 62 type:"POST", 63 datatype:"JSON", //好像无用,还是要使用JSON.parse(),不然无法获取 64 success:function (arg) { 65 var data = JSON.parse(arg); 66 if(data.status){ 67 // 重定向url 68 window.location.replace("../log_success") 69 } 70 {# console.log(data.error);#} 71 for(key in data.error){ 72 {# console.log(data.error[key][0]);#} 73 document.getElementById(key).innerHTML = data.error[key][0]; 74 } 75 if(!data.check_code){ 76 $("#check_code").html("验证码错误") 77 } 78 79 } 80 }) 81 } 82 function img(ths) { 83 console.log(111); 84 //给url加?可以重新获取 85 ths.src = ths.src+"?"; 86 {# $(ths).attr("src","../create_checkcode");#} 87 } 88 </script> 89 90 </body> 91 </html>
二、url别名反推
name是别名通过别名在views.py和html中都可以反向生成url
在views.py中
from django.urls import reverse
对于有分组名的url
current_path = reverse("name",kwargs = {"分组名":参数})
没有的
current_path = reverse("name",args = (参数1,参数2......))
在html中
{% url "name" 分组名 = 参数%} 或者没有分组名的时候直接写参数