Django---登陸(含隨機生成圖片驗證碼)、註冊示例講解

登陸(驗證碼)、註冊功能具體代碼

 # urls.py

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)  #註冊

]

 # views.py

# 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)

# login.html

<!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>

 

# register.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>

 

# models.py

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標籤中發送請求(有個特殊功能)

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

視圖函數中,引入JsonResponse,用次返回數據,沒必要再轉換成就送數據,而前臺接收到數據,也不須要反序列化,這些步驟在內部已經封裝好了。

from django.http import JsonResponse

return JsonResponse({"user":user,"error":""})

 

五、字母與ASCII的對應

a ~ z      97 ~ 122

A ~ Z     65 ~ 90

六、Form組件中  errors中的 __all__

在全局的鉤子中,其錯誤直接 raise ValidationError("用戶密碼不一致"),會存儲在errors的__all__中

form = UserForm(request.POST)

if form.is_valid():
  form.cleaned_data

else:
  form.errors    #是個字典
  form.errors.get("__all__")   #全局鉤子中的具體錯誤

可是全局鉤子若是是如下,全局的錯誤會存儲在r_pwd中:

相關文章
相關標籤/搜索