Day 20/12/30

圖檔驗證碼登入
生成圖檔驗證碼
pip install pillow
# -*- coding = utf-8 -*-
# @Time : 2020/12/29 16:09
# @Author : Chenih
# @File : image_code.py
# @Software : PyCharm
from PIL import Image, ImageDraw, ImageFilter, ImageFont
import random
"""繪制圖檔驗證碼"""
def check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成随機字母
:return:
"""
return chr(random.randint(65, 90))
def rndColor():
"""
生成随機顔色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 寫文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
# 寫幹擾點
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 寫幹擾圓圈
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
# 畫幹擾線
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=rndColor())
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)
if __name__ == '__main__':
image_obj, code = check_code()
image_obj.show() # 直接打開
# 2. 寫入檔案
# img,code = check_code()
# with open('code.png','wb') as f:
# img.save(f,format='png')
# 3. 寫入記憶體
# from io import BytesIO
# stream = BytesIO()
# img.save(stream, 'png')
# stream.getvalue()
圖檔驗證碼路由
驗證碼圖檔的視圖函數
def image_code(request):
"""生成圖檔驗證碼"""
# 調用函數生成圖檔驗證碼
image_obj, code = check_code()
# 将驗證碼字元存入session
request.session['code'] = code
request.session.set_expiry(60)
# 建立一個記憶體空間
stream = BytesIO()
# 将生成的圖檔驗證碼儲存在記憶體空間中
image_obj.save(stream, 'png')
# 将從記憶體空間擷取的圖檔驗證碼傳給前端
return HttpResponse(stream.getvalue())
頁面顯示
{% extends 'layout/basic.html' %}
{% load static %}
{% block title %} 郵箱|手機号 登入 {% endblock %}
{% block css %}
<link rel="stylesheet" href="{% static 'css/account.css' %}">
<style>
.error-msg {
color: red;
position: absolute;
font-size: 13px;
}
</style>
{% endblock %}
{% block content %}
<div class="account">
<div class="title">郵箱|手機号 登入</div>
<form id="smsForm" method="POST" novalidate>
{% csrf_token %}
{% for field in form %}
{% if field.name == 'code' %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<div class="row">
<div class="col-xs-7">
{{ field }}
<span class="error-msg">{{ field.errors.0 }}</span>
</div>
<div class="col-xs-5">
{# 從image_code中拿到生成的圖檔 #}
<img src="{% url 'image_code' %}" id="imageCode" title="點選更換圖檔" alt="">
</div>
</div>
</div>
{% else %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg">{{ field.errors.0 }}</span>
</div>
{% endif %}
{% endfor %}
<div>
<div style="float: right">
<a href="{% url 'loginsms' %}">短信驗證碼登入?</a>
</div>
</div>
<div class="row">
<div class="col-xs-3">
<input type="submit" class="btn btn-primary" value="登 錄"/>
</div>
</div>
</form>
</div>
{% endblock %}
{% block js %}
<script>
$(function () {
$('#imageCode').click(function () {
var oldSrc = $(this).attr('src');
$(this).attr('src', oldSrc + '?');
})
})
</script>
{% endblock %}
驗證碼圖檔的點選更換:
給圖檔<img src="{% url 'image_code' %}" id="imageCode" title="點選更換圖檔" alt="">設定id,平且給此id添加點選事件。
{% block js %}
<script>
$(function () {
// 找到id為imageCode,添加點選事件
$('#imageCode').click(function () {
// 定義變量oldSrc,拿到目前id的src屬性的值(圖檔位址)
var oldSrc = $(this).attr('src');
// 每點選一次就将目前id所在的src的值加一個?(用來替換圖檔)
// oldSrc -> oldSrc? -> oldSrc?? -> ...
$(this).attr('src', oldSrc + '?');
})
})
</script>
{% endblock %}
登入
def login(request):
"""使用者名密碼登入"""
if request.method == 'GET':
form = LoginForm(request)
return render(request, 'login.html', {'form': form})
form = LoginForm(request, data=request.POST)
if form.is_valid():
# 擷取資料時寫的name為username,實際上擷取的是手機号或者郵箱
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# user_obj = models.User.objects.filter(username=username, password=password).first()
# 使用Q對象構造複雜的查詢對象(判斷是用email還是phone登入的)
user_obj = models.User.objects.filter(Q(email=username) | Q(phone=username)).filter(password=password).first()
if user_obj:
# 如果此使用者存在,那麼将使用者的id儲存在session中
request.session['user_id'] = user_obj.pk
request.session.set_expiry(60*60*24*14)
return redirect('index')
# 若不存在此使用者,則抛出錯誤提示
form.add_error('username', '使用者名或密碼有誤')
return render(request, 'login.html', {'form': form})