from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path("login/",views.login), #登陸 path("get_valid_img/",views.get_valid_img), #生成驗證碼 path("reg/",views.reg) #註冊 ]
# Create your views here. import random import re from io import BytesIO from PIL import Image, ImageDraw, ImageFont from django import forms from django.contrib import auth from django.core.exceptions import ValidationError from django.forms import widgets from django.http import JsonResponse from django.shortcuts import render, HttpResponse from app01.models import UserInfo ###################### 建立UserForm用戶校驗,輸入的內容是否合法############## class UserForm(forms.Form): user = forms.CharField(min_length=5, label='用戶名') pwd = forms.CharField(min_length=5, widget=widgets.PasswordInput(), label="密碼") r_pwd = forms.CharField(min_length=5, widget=widgets.PasswordInput(), label="確認密碼") email = forms.EmailField(min_length=5, label="郵箱") # 爲每個字段 input 添加類名 form-control def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for filed in self.fields.values(): filed.widget.attrs.update({'class': 'form-control'}) def clean_user(self): val = self.cleaned_data.get('user') user = UserInfo.objects.filter(username=val).first() if user: raise ValidationError('用戶名已存在!') else: return val def clean_pwd(self): val = (self.cleaned_data.get('pwd')) if val.isdigit(): raise ValidationError('密碼不能爲純數字!') else: return val def clean_email(self): val = self.cleaned_data.get('email') if re.search("\w+@163.com$", val): return val else: raise ValidationError('郵箱必須是163格式郵箱!') def clean(self): # 全局校驗 pwd = self.cleaned_data.get('pwd') r_pwd = self.cleaned_data.get('r_pwd') if pwd and r_pwd and pwd != r_pwd: # raise ValidationError("兩次密碼不一致!") # 也能夠採用如下方法,這樣在渲染的時候能夠不用特殊處理,全局的錯誤會在r_pwd中,再也不是__all__ self.add_error("r_pwd", ValidationError('兩次密碼不一致!')) else: return self.cleaned_data ####################### 登陸 ###################### def login(request): if request.method == "GET": return render(request, "login.html") else: user = request.POST.get("user") pwd = request.POST.get("pwd") validcode = request.POST.get("validcode") res = {"user": None, "error_msg": ""} if validcode.upper() == request.session.get("keep_str").upper(): user_obj = auth.authenticate(username=user, password=pwd) if user_obj: res["user"] = user else: res["error_msg"] = "用戶名或密碼錯誤!" else: res["error_msg"] = "驗證碼錯誤" return JsonResponse(res) ####################### 生成驗證碼 ################################ def get_valid_img(request): def get_random_color(): return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # 生成圖片 img = Image.new("RGB", (250, 35), get_random_color()) draw = ImageDraw.Draw(img) font = ImageFont.truetype("static/font/kumo.ttf", 32) keep_str = '' # 用於存儲驗證碼,用戶後臺校驗 # 爲圖片添加隨機文本text for i in range(6): rand_num = str(random.randint(0, 9)) rand_lowalp = chr(random.randint(97, 122)) rand_upealp = chr(random.randint(65, 90)) random_char = random.choice([rand_num, rand_lowalp, rand_upealp]) draw.text((i * 30 + 50, 0), random_char, get_random_color(), font=font) keep_str += random_char # --------加噪點和噪線------ width = 250 height = 35 for i in range(3): x1 = random.randint(0, width) x2 = random.randint(0, width) y1 = random.randint(0, height) y2 = random.randint(0, height) draw.line((x1, y1, x2, y2), fill=get_random_color()) for i in range(2): draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color()) x = random.randint(0, width) y = random.randint(0, height) draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color()) # 將生成的圖片進行讀寫 f = BytesIO() # 寫,在內存中建立文件句柄 img.save(f, "png") # 將img保存在句柄中 data = f.getvalue() # 讀取圖片字節,返回給img響應 # 生成的隨機字符串,加到sesstion中,傳給用戶,在用戶登陸時候進行校驗,不能將隨機字符串做爲全局變量 request.session["keep_str"] = keep_str # 將圖片字節 直接響應回圖片 return HttpResponse(data) ########################## 註冊 ########################## def reg(request): if request.method == "GET": userform = UserForm() return render(request, "reg.html", locals()) else: form = UserForm(request.POST) res = {"user": None, "err_msg": ""} if form.is_valid(): user = form.cleaned_data.get('user') pwd = form.cleaned_data.get('pwd') email = form.cleaned_data.get('email') UserInfo.objects.create_user(username=user, password=pwd, email=email) res['user'] = user else: res['err_msg'] = form.errors return JsonResponse(res)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Login</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <style type="text/css"> body{ background:url(/static/img/小橋.jpg); background-size:100%; background-attachment: fixed; } </style> </head> <body> <h1 class="text-primary" style="text-align: center;line-height:150px">登陸頁面</h1> <div class="container"> <div class="row"> <div class="col-lg-4 col-md-offset-4"> {# <form action="" method="post">#} {% csrf_token %} <div class="form-group"> <label for="">用戶名</label> <input type="text" class="form-control " placeholder="用戶名" id="user"> </div> <div class="form-group"> <label for="">密碼</label> <input type="password" class="form-control" placeholder="密碼" id="pwd"> </div> <div class="form-group"> <label for="">驗證碼</label> <div class="row"> <div class="col-md-6"> <input type="text" class="form-control" placeholder="驗證碼" id="validcode"> </div> <div class="col-md-6"> <img width="165" height="35" src="/get_valid_img/" alt="" id="img"> </div> </div> </div> <input type="button" class="btn btn-primary btn-block pull-right login_btn" value="登陸"> <p><a href="/reg/" style="text-align: center;display: block">尚未帳號,去註冊?</a></p> <span class="error"></span> {# </form>#} </div> </div> </div> <script src="/static/js/jquery.js"></script> <script type = "text/javascript"> window.onload = function() { var config = { vx : 4, vy : 4, height : 2, width : 2, count : 100, color : "121, 162, 185", stroke : "100, 200, 180", dist : 6000, e_dist : 20000, max_conn : 10 } CanvasParticle(config); } </script> <script type = "text/javascript" src="/static/js/canvas-particle.js"></script> <script> //登陸數據 $(".login_btn").click(function () { console.log(6666) $.ajax({ url:"/login/", type:"post", data:{ user:$("#user").val(), pwd:$("#pwd").val(), validcode:$("#validcode").val(), csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() }, success:function (response) { {#console.log(response.user);#} if(response.user){ //登錄成功 console.log(111111); location.href="/homepage/"; {#alert(111111)#} } else{ //登錄失敗 $(".error").html(response.err_msg).css("color","reg") } } }) }) //驗證碼刷新 $("#img").click(function () { this.src+="?" }) </script> </body> </html>
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Register</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <style type="text/css"> body{ background:url(/static/img/山水.jpg); background-size:100%; background-attachment: fixed; } </style> </head> <body> <h1 class="text-primary" style="text-align: center;line-height:150px">註冊頁面</h1> <div class="container"> <div class="row"> <div class="col-lg-4 col-md-offset-4"> {% csrf_token %} <div class="form-group"> <label for="">用戶名</label> <input type="text" class="form-control" placeholder="用戶名" id="user"> <span class="error pull-right"></span> </div> <div class="form-group"> <label for="">密碼</label> <input type="password" class="form-control" placeholder="密碼" id="pwd"> <span class="error pull-right"></span> </div> <div class="form-group"> <label for="">確認密碼</label> <input type="password" class="form-control" placeholder="確認密碼" id="r_pwd"> <span class="error pull-right"></span> </div> <div class="form-group"> <label for="">郵箱</label> <input type="email" class="form-control" placeholder="郵箱" id="email"> <span class="error pull-right"></span> </div> <input type="button" class="btn btn-primary btn-block pull-right" id="reg_btn" value="註冊"> <p><a href="/login/" style="text-decoration:none; text-align: center;display: block">已註冊,請點擊登陸</a></p> <span class="error pull-right"></span> </div> </div> </div> <script src="/static/js/jquery.js"></script> <script type = "text/javascript"> window.onload = function() { var config = { vx : 4, vy : 4, height : 2, width : 2, count : 100, color : "121, 162, 185", stroke : "100, 200, 180", dist : 6000, e_dist : 20000, max_conn : 10 } CanvasParticle(config); } </script> <script type = "text/javascript" src="/static/js/canvas-particle.js"></script> <script> //註冊數據 $("#reg_btn").click(function () { console.log(1111); $.ajax({ url:"/reg/", type:"post", data:{ csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), user:$("#user").val(), pwd: $("#pwd").val(), r_pwd:$("#r_pwd").val(), email:$("#email").val(), }, success:function (response) { console.log(response); if (response.user){ //註冊成功 location.href="/login/" } else{ //清除錯誤 $(".error").html(""); $(".form-group").removeClass("has-error"); //展現錯誤 $.each(response.err_msg,function (i,j) { $("#"+i).next().html(j[0]).css("color","red").parent().addClass("has-error") }) } } }) }) </script> </body> </html>
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): tel = models.CharField(max_length=32)
用戶認證組件中驗證的信息是存儲信息是依賴於 auth_user 表中的,可是該表的中字段是有限的,好比註冊的時候想輸入手機號等,所以,想要擴展user表,咱們就須要建立一個新的userinfo表來代替auth_user 表。javascript
須要在 setting 中設置(項目爲app01,models表爲UserInfo):css
AUTH_USER_MODEL="app01.UserInfo"
models中建立的表須要繼承 AbstractUser,其實 auth_user 也是繼承了該類,所以,新建立的表就有了原來表中的字段還能夠添加新字段html
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): #繼承 tel = models.CharField(max_length=32)
數據庫的遷移:java
python manage.py makemigrations
python manage.py migrate
#在數據庫auth_user或其替表明中,建立數據(經過終端)建立超級用戶 createsuperuser
img標籤有一個特殊的功能,去發送請求,能夠實現圖片的局部刷新,典型的是驗證碼圖片的刷新,python
加問號,等於屢次訪問該地址,而驗證碼中該地址每次訪問都會獲取不一樣的隨機驗證碼圖片,所以能夠實現局部的刷新驗證碼jquery
{# 驗證碼的刷新 #} $("#valid_img_btn").click(function () { this.src += "?" });
登陸驗證的時候,如何校驗驗證碼?git
後臺中在生成驗證碼的方法 獲取的隨機字符串 爲 keep_str , 可是在login方法中,接收的數據如何跟 其餘方法中的 keep_str 進行比較?ajax
有人說,將keep_str 存成全局變量 gloabl, 這樣是能夠知足比較,可是不一樣的用戶要有不一樣的驗證碼,這樣的話,只有最後用戶刷新頁面生成的驗證碼纔是真的,有用戶1在登陸界面,尚未來得及輸入,其餘用戶2也進入登陸界面,那麼驗證碼發生了變化,用戶1 根據頁面展現的驗證碼即使輸入正確也會登陸失敗。數據庫
所以,咱們要將各用戶的驗證碼存到各自的 session 中: django
# 設置session request.session[keep_str":keep_str] # 獲取session request.session.get("keep_str")
session 或者 用戶認證組件,都會在 django-session表中生成記錄,
一個瀏覽器訪問會有一條記錄,兩個瀏覽器訪問會有2條記錄,裏面的記錄個數與訪問的瀏覽器的個數一致。
session 不只能夠用於登陸,校驗驗證碼,之後還會有不少的用處。
視圖函數中,引入JsonResponse,用次返回數據,沒必要再轉換成就送數據,而前臺接收到數據,也不須要反序列化,這些步驟在內部已經封裝好了。
from django.http import JsonResponse
return JsonResponse({"user":user,"error":""})
a ~ z 97 ~ 122
A ~ Z 65 ~ 90
在全局的鉤子中,其錯誤直接 raise ValidationError("用戶密碼不一致"),會存儲在errors的__all__中
form = UserForm(request.POST) if form.is_valid(): form.cleaned_data else: form.errors #是個字典 form.errors.get("__all__") #全局鉤子中的具體錯誤
可是全局鉤子若是是如下,全局的錯誤會存儲在r_pwd中: