11、Django邮箱||验证码||登录
创建 django 项目, APP 略.....
准备工作
1. Model的编写
model.py
from django.db import models
gender = (
('男','男'),
('女','女'),
)
class Before_User(models.Model):
name = models.CharField(max_length=128, null=False, verbose_name='用户名')
password = models.CharField(max_length=256, null=False, verbose_name='密码')
email = models.EmailField(unique=True, null=False, verbose_name='邮箱')
sex = models.CharField(max_length=32, choices=gender, default='男', verbose_name='性别')
is_active = models.BooleanField(default=False)
c_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
def __str__(self):
return self.name
class Meta:
ordering = ('-c_time',)
db_table = 'bf_user'
verbose_name = '前端注册用户'
verbose_name_plural = verbose_name
2.第三方库安装
pipenv install django--simple-captcha
pipenv install python-memcached
3. 注册APP
admin.py 注册
from django.contrib import admin
from .models import Before_User
admin.site.register(Before_User)
4. 生成数据库
python manage.py makemigrations
python manage.py migrate
4.django 后台创建一个注册用户(略)
setting.py
INSTALLED_APPS = [
'''略'''
'Apply_users', # 前端注册用户
'captcha',
]
# 发送邮箱验证码
EMAIL_HOST = "smtp.163.com" # 服务器
EMAIL_PORT = 25 # 一般情况下都为25
EMAIL_HOST_USER = "xxxxx@163.com" # 账号
EMAIL_HOST_PASSWORD = "xxxxx" # 密码 (注意:这里的密码指的是授权码)
EMAIL_USE_TLS = False # 一般都为False
EMAIL_FROM = "xxxxx@163.com" # 邮箱来自
# 定义memcache服务器连接
import memcache
CACHES = {
'default':{
'BACKEND':'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'10.10.181.18:11211',
],
'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key #自定义存储格式
}
}
url.py 路径信息
from django.urls import path, re_path
from . import views
urlpatterns = [
path('index/', views.index, name='bf_index'),
path('login/', views.LoginView.as_view(), name='bf_login'),
path('register/', views.RegisterView.as_view(), name='bf_register'),
path('logout', views.logout, name='bf_logout'),
path('email_code/', views.email_code, name='bf_email_code'), # 发送邮箱验证码
re_path('forgetpwd/$', views.ForgetPwdView.as_view(), name='bf_forgetpwd'), # 忘记密码,验证邮件
]
forms.py 验证
from django import forms
# from django.core import validators
from .models import Before_User, gender
from captcha.fields import CaptchaField
from django.contrib.auth.hashers import make_password, check_password
# 自定义 base 错误类
class BaseForm(forms.Form):
def get_errors(self):
errors = self.errors.get_json_data()
new_errors = {}
for key,message_dicts in errors.items():
messages = []
for message_dict in message_dicts:
message = message_dict['message']
messages.append(message)
new_errors[key] = messages
return new_errors
# 登录form验证
class LoginViewForm(BaseForm):
'''
登录Form
attrs:可自定义html属性
'''
email = forms.EmailField(label='邮箱', widget=forms.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(label='密码', max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
captcha = CaptchaField(label='验证码', error_messages={'invalid': '验证码错误'})
def clean(self):
cleaned_data = super().clean()
email = cleaned_data.get('email')
password = cleaned_data.get('password')
user = Before_User.objects.filter(email=email).first()
if not user.is_active:
raise forms.ValidationError(message='你的账户已被禁止登陆,请联系管理员')
if user and check_password(password, user.password):
cleaned_data.update({'id': user.id, 'name': user.name})
return cleaned_data
raise forms.ValidationError(message='邮箱或者密码错误!')
# 注册form验证
class RegisterForm(BaseForm):
'''注册Form'''
name = forms.CharField(max_length=128, label='用户名', widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='邮箱', widget=forms.EmailInput(attrs={'class': 'form-control'}))
sex = forms.ChoiceField(label='性别', choices=gender)
password = forms.CharField(label='密码', max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
password2 = forms.CharField(label='确认密码', max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
captcha = CaptchaField(label='验证码')
code = forms.CharField(label='邮箱验证码', max_length=50, widget=forms.TextInput(attrs={'class': 'form-control'}))
def clean_email(self):
email = self.cleaned_data.get('email')
exists = Before_User.objects.filter(email=email).exists()
if exists:
raise forms.ValidationError(message='邮箱已被注册')
return email
def clean_password(self):
password = self.cleaned_data.get('password')
if len(password) < 6:
raise forms.ValidationError("密码长度小于6位")
elif len(password) > 20:
raise forms.ValidationError('密码长度大于20位')
return password
def clean_password2(self):
password = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError(message='两次密码输入不一致')
return password2
def clean_code(self):
from django.core.cache import cache
code = self.cleaned_data.get('code')
email = self.cleaned_data.get('email')
cache_code = cache.get(email)
if cache_code != code:
raise forms.ValidationError(message='邮箱验证码错误')
return code
# 修改密码 form 验证
class ForgetPwdForm(BaseForm):
email = forms.EmailField(label='邮箱', widget=forms.EmailInput(attrs={'class': 'form-control'}))
code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control'}))
def clean_email(self):
email = self.cleaned_data.get('email')
exists = Before_User.objects.filter(email=email).exists()
if exists:
return email
raise forms.ValidationError('无此邮箱用户,请检查你的邮箱是否有误')
def clean_code(self):
from django.core.cache import cache
code = self.cleaned_data.get('code')
db_code = cache.get(self.cleaned_data.get('email'))
if code != db_code:
raise forms.ValidationError('邮箱验证码错误')
return code
send_mail.py
from random import Random # 用于生成随机码
from django.core.mail import send_mail # 发送邮件模块
from django.conf import settings # setting.py添加的的配置信息
from django.core.cache import cache
import smtplib
import logging
from django.contrib.auth.hashers import make_password
from .models import Before_User
logger = logging.getLogger(__name__)
# 生成随机字符串
def random_str(randomlength=4):
"""
随机字符串
:param randomlength: 字符串长度
:return: String 类型字符串
"""
str = ""
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length = len(chars) - 1
random = Random()
for i in range(randomlength):
str += chars[random.randint(0, length)]
return str
# 发送电子邮件
def send_code_email(email):
"""
发送电子邮件
"""
code = random_str(4)
cache.set(email, code, 120)
email_title = "Django"
email_body = "您的邮箱验证码为:{0}, 该验证码有效时间为两分钟,请及时进行验证。".format(code)
try:
send_mail(email_title, email_body, settings.EMAIL_FROM, [email])
return {'code': 200, 'message': '邮箱发送成功,请查收'}
except smtplib.SMTPRecipientsRefused:
return {'code': 404, 'message': '未找到此邮箱'}
except Exception as e:
logger.error("系统邮件配置有误,请检查......")
return {'code': 500, 'message': '服务内部错误,请稍等,着急请联系管理员......'}
# 忘记密码发送修改过的密码给用户的邮件
def send_accout_email(email):
email_title = "Django密码修改:"
new_pwd = random_str(16)
email_body = "邮箱: {0}\n 密码: {1}\n 这是系统随机设置密码,请及时进行修改。".format(email, new_pwd)
try:
send_mail(email_title, email_body, settings.EMAIL_FROM, [email])
mf_user = Before_User.objects.get(email=email)
mf_user.password = make_password(new_pwd)
mf_user.save()
return {'code': 200, 'message': '密码修改信息已发送到你邮箱,请查收'}
except smtplib.SMTPRecipientsRefused:
return {'code': 404, 'message': '未找到此邮箱'}
except Exception as e:
logger.error("系统邮件配置有误,请检查......")
return {'code': 500, 'message': '服务内部错误,请稍等,或者请联系管理员......'}
views.py
from django.shortcuts import render, redirect,reverse
from django.views.generic import View
from django.http import JsonResponse
from .forms import LoginViewForm, RegisterForm, ForgetPwdForm
from .models import Before_User
from django.contrib.auth.hashers import make_password
from .send_email import send_code_email, send_accout_email
def index(request):
return render(request, 'bf/bf_index.html')
# 注册使用
class RegisterView(View):
def get(self, request):
if request.session.get('is_login', None):
return redirect(reverse("bf_index"))
register_form = RegisterForm()
return render(request, 'bf/bf_register.html',locals())
def post(self, request):
register_form = RegisterForm(request.POST)
if register_form.is_valid():
name = register_form.cleaned_data.get('name')
email = register_form.cleaned_data.get('email')
sex = register_form.cleaned_data.get('sex')
password = register_form.cleaned_data.get('password')
new_user = Before_User.objects.create(name=name, email=email, sex=sex, password=make_password(password), is_active=True)
new_user.save()
return redirect(reverse('bf_login'))
message = [item[0] for item in register_form.errors.values()]
message = ','.join(message)
return render(request, 'bf/bf_register.html', locals())
# 登录使用
class LoginView(View):
def get(self, request):
if request.session.get('is_login', None):
return redirect(reverse("bf_index"))
login_form = LoginViewForm()
return render(request, 'bf/bf_login.html', locals())
def post(self, request):
login_form = LoginViewForm(request.POST)
if login_form.is_valid():
user_id = login_form.cleaned_data.get('id')
user_name = login_form.cleaned_data.get('name')
request.session['is_login'] = True
request.session['user_id'] = user_id
request.session['user_name'] = user_name
return redirect(reverse('bf_index'))
message = [item[0] for item in login_form.errors.values()]
message = ','.join(message)
return render(request, 'bf/bf_login.html', locals())
# 忘记密码视图并发送修改后的密码给用户
class ForgetPwdView(View):
def get(self, request):
FORGETPWD_FORM = ForgetPwdForm()
return render(request, 'bf/bf_forgetpwd.html', locals())
def post(self, request):
FORGETPWD_FORM = ForgetPwdForm(request.POST)
if FORGETPWD_FORM.is_valid():
email = FORGETPWD_FORM.cleaned_data.get('email')
send_accout_email(email=email)
return redirect(reverse('bf_login'), locals())
message = [item[0] for item in FORGETPWD_FORM.errors.values()]
message = ','.join(message)
return render(request, 'bf/bf_forgetpwd.html', locals())
# 登出使用
def logout(request):
if not request.session.get('is_login', None):
return redirect(reverse('bf_index'))
request.session.flush()
# 或者使用下面的方法
# del request.session['is_login']
# del request.session['user_id']
# del request.session['user_name']
return render(request, 'bf/bf_index.html')
# 发送邮箱验证码 url 视图函数
def email_code(request, methods=['POST']):
email = request.POST.get('email')
data = send_code_email(email)
return JsonResponse(data, safe=False)
摸版 templates
bf_base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %} {% endblock%}
</title>
</head>
<body>
{% block content %} {% endblock %}
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
$(function () {
// Add refresh button after field (this can be done in the template as well)
// $('img.captcha').after(
// $('<a class="btn btn-sm text-white btn-info pull-right captcha-refresh">看不清</a>')
// );
// 点击图形验证码切换效果
$('.captcha').click(function () {
var $form = $(this).parents('form');
var url = location.protocol + "//" + window.location.hostname + ":"
+ location.port + "/captcha/refresh/";
// Make the AJAX-call
$.getJSON(url, {}, function (json) {
$form.find('input[name="captcha_0"]').val(json.key);
$form.find('img.captcha').attr('src', json.image_url);
});
return false;
});
});
</script>
<script>
// 发送邮件,并倒计时
$(function() {
$('.code').click(function(event){
event.preventDefault();
var self = $(this);
var email = $("input[name='email']").val();
var csrfmiddlewaretoken = $("[name='csrfmiddlewaretoken']").val();
$.post({
'url': '{% url "bf_email_code" %}',
'data': {
'email': email,
'csrfmiddlewaretoken': csrfmiddlewaretoken
},
success: function (data) {
if (data['code'] == 200) {
alert('邮箱验证码发送成功!');
self.attr("disabled", true);
var timeCount = 60;
var timer = setInterval(function () {
timeCount--;
self.attr(timeCount);
if (timeCount <= 0) {
self.removeAttr('disabled');
clearInterval(timer);
self.text('发送验证码');
}
}, 1000);
} else {
alert(data['message']);
}
}
})
})
})
</script>
</body>
</html>
bf_login.html
<div data-gb-custom-block data-tag="extends" data-0='bf/bf_base.html'></div>
<div data-gb-custom-block data-tag="block">
登陆页面
</div>
<div data-gb-custom-block data-tag="block"></div>
<form action="<div data-gb-custom-block data-tag="url" data-0='bf_login'></div>" method="post">
<div data-gb-custom-block data-tag="csrf_token"></div>
<div data-gb-custom-block data-tag="if">
{{ message }}
</div>
<p>
{{ login_form.email.label_tag }}
{{ login_form.email }}
</p>
<p>
{{ login_form.password.label_tag }}
{{ login_form.password }}
</p>
<p>
{{ login_form.ca{% extends 'bf/bf_base.html'%}
{% block title %}
登陆页面
{% endblock %}
{% block content %}
<form action="{% url 'bf_login' %}" method="post">
{% csrf_token %}
{% if message %}
{{ message }}
{% endif %}
<p>
{{ login_form.email.label_tag }}
{{ login_form.email }}
</p>
<p>
{{ login_form.password.label_tag }}
{{ login_form.password }}
</p>
<p>
{{ login_form.captcha.errors }}
{{ login_form.captcha.label_tag }}
{{ login_form.captcha }}
</p>
<input type="submit" value="登录">
</form>
<a href="{% url 'bf_forgetpwd' %}">忘记密码?</a>
<a href="{% url 'bf_register' %}">注册</a>
{% endblock %}{% extends 'bf/bf_base.html'%}
{% block title %}
登陆页面
{% endblock %}
{% block content %}
<form action="{% url 'bf_login' %}" method="post">
{% csrf_token %}
{% if message %}
{{ message }}
{% endif %}
<p>
{{ login_form.email.label_tag }}
{{ login_form.email }}
</p>
<p>
{{ login_form.password.label_tag }}
{{ login_form.password }}
</p>
<p>
{{ login_form.captcha.errors }}
{{ login_form.captcha.label_tag }}
{{ login_form.captcha }}
</p>
<input type="submit" value="登录">
</form>
<a href="{% url 'bf_forgetpwd' %}">忘记密码?</a>
<a href="{% url 'bf_register' %}">注册</a>
{% endblock %}
bf_register.html
{% extends 'bf/bf_base.html'%}
{% block title %}
注册页面
{% endblock %}
{% block content %}
<form action="{% url 'bf_register' %}" method="post">
{% csrf_token %}
<!-- 显示全部错误信息 -->
{% if message %}
{{ message }}
{% endif %}
<p>
{{ register_form.name.label_tag }}
{{ register_form.name }}
</p>
<p>
{{ register_form.email.label_tag }}
{{ register_form.email }}
</p>
<p>
{{ register_form.sex.label_tag }}
{{ register_form.sex }}
</p>
<p>
{{ register_form.password.label_tag }}
{{ register_form.password }}
</p>
<p>
{{ register_form.password2.label_tag }}
{{ register_form.password2 }}
</p>
<p>
{{ register_form.captcha.errors }}
{{ register_form.captcha.label_tag }}
{{ register_form.captcha }}
</p>
<p>
{{ register_form.code.label_tag }}
{{ register_form.code }}
<!-- 只显示指定 form 验证错误信息-->
{% if register_form.errors.code %}
<span>{{ register_form.errors.email_captcha }}</span>
{% endif %}
<input type="submit" value="点击发送" class="code">
</p>
<input type="reset" value="重置">
<input type="submit" value="注册">
</form>
{% endblock %}
bf_forget.html
{% extends 'bf/bf_base.html'%}
{% block title %}
忘记密码
{% endblock %}
{% block content %}
<form action="{% url 'bf_forgetpwd' %}" method="post">
{% csrf_token %}
{% if message %}
{{ message }}
{% endif %}
<p>
{{ FORGETPWD_FORM.email.label_tag }}
{{ FORGETPWD_FORM.email }}
</p>
<p>
{{ FORGETPWD_FORM.code.label_tag }}
{{ FORGETPWD_FORM.code }}
<input type="submit" value="点击发送" class="code">
</p>
<input type="submit" value="提交">
</form>
{% endblock %}
bf_index.html
{% extends 'bf/bf_base.html'%}
{% block title %}
首页
{% endblock %}
{% block content %}
{% if request.session.is_login %}
welcome {{ request.session.user_name }}!
{% else %}
未登录
{% endif %}
{% endblock %}
登录+验证码
注册+验证码
忘记密码验证
Last updated