在Python中已经内置了一个smtp邮件发送模块,Django在此基础上进行了简单地封装,让我们在Django环境中可以更方便更灵活的发送邮件。
所有的功能都在django.core.mail中。
首先settings里面设置
# settings.py EMAIL_HOST = "smtp.qq.com" # SMTP服务器主机,默认qq邮箱是不开启的,需要用户自行开启 EMAIL_PORT = 25 # 端口 EMAIL_HOST_USER = "19@qq.com" # 邮箱地址 EMAIL_HOST_PASSWORD = "dwjybikexxxxxxxx" # 密码 EMAIL_USE_TLS= True EMAIL_FROM = "1184405959@qq.com" # 邮箱地址
在apps目录新建package utils,然后新建一个email_send.py文件
# apps/utils/email_send.py from random import Random from django.core.mail import send_mail from users.models import EmailVerifyRecord from MxOnline.settings import EMAIL_FROM # 生成随机字符串 def random_str(random_length=8): str = '' # 生成字符串的可选字符串 chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789' length = len(chars) - 1 random = Random() for i in range(random_length): str += chars[random.randint(0, length)] return str # 发送注册邮件 def send_register_eamil(email, send_type="register"): # 发送之前先保存到数据库,到时候查询链接是否存在 # 实例化一个EmailVerifyRecord对象 email_record = EmailVerifyRecord() # 生成随机的code放入链接 code = random_str(16) email_record.code = code email_record.email = email email_record.send_type = send_type email_record.save() # 定义邮件内容: email_title = "" email_body = "" if send_type == "register": email_title = "NBA注册激活链接" email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,发件人邮箱地址,收件人(是一个字符串列表) send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果发送成功 if send_status: pass
用户的激活:
根据邮箱找到对应的用户,然后设置is_active = True来实现
# 激活用户 class ActiveUserView(View): def get(self, request, active_code): # 查询邮箱验证记录是否存在 all_record = EmailVerifyRecord.objects.filter(code = active_code) if all_record: for record in all_record: # 获取到对应的邮箱 email = record.email # 查找到邮箱对应的user user = UserProfile.objects.get(email=email) user.is_active = True user.save() # 验证码不对的时候跳转到激活失败页面 else: return render(request,'active_fail.html') # 激活成功跳转到登录页面 return render(request, "login.html", )
在templates目录下创建 active_fail.html,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p style="color: red;">链接失效</p> </body> </html>
修改login视图
添加一个判断,用户注册的后,等激活才能登陆
# users/views.py from django.shortcuts import render from django.contrib.auth import authenticate,login from django.contrib.auth.backends import ModelBackend from .models import UserProfile,EmailVerifyRecord from django.db.models import Q from django.views.generic.base import View from .forms import LoginForm,RegisterForm from django.contrib.auth.hashers import make_password from utils.email_send import send_register_eamil #邮箱和用户名都可以登录 # 基础ModelBackend类,因为它有authenticate方法 class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: # 不希望用户存在两个,get只能有一个。两个是get失败的一种原因 Q为使用并集查询 user = UserProfile.objects.get(Q(username=username)|Q(email=username)) # django的后台中密码加密:所以不能password==password # UserProfile继承的AbstractUser中有def check_password(self, raw_password): if user.check_password(password): return user except Exception as e: return None class LoginView(View): '''用户登录''' def get(self,request): return render(request, 'login.html') def post(self,request): # 实例化 login_form = LoginForm(request.POST) if login_form.is_valid(): # 获取用户提交的用户名和密码 user_name = request.POST.get('username', None) pass_word = request.POST.get('password', None) # 成功返回user对象,失败None user = authenticate(username=user_name, password=pass_word) # 如果不是null说明验证成功 if user is not None: if user.is_active: # 只有注册激活才能登录 login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', {'msg': '用户名或密码错误', 'login_form': login_form}) # 只有当用户名或密码不存在时,才返回错误信息到前端 else: return render(request, 'login.html', {'msg': '用户名或密码错误','login_form':login_form}) # form.is_valid()已经判断不合法了,所以这里不需要再返回错误信息到前端了 else: return render(request,'login.html',{'login_form':login_form}) # 激活用户的view class ActiveUserView(View): def get(self, request, active_code): # 查询邮箱验证记录是否存在 all_record = EmailVerifyRecord.objects.filter(code = active_code) if all_record: for record in all_record: # 获取到对应的邮箱 email = record.email # 查找到邮箱对应的user user = UserProfile.objects.get(email=email) user.is_active = True user.save() # 激活成功跳转到登录页面 return render(request, "login.html", ) # 自己瞎输的验证码 else: return render(request, "register.html", {"msg": "您的激活链接无效"}) class RegisterView(View): '''用户注册''' def get(self,request): register_form = RegisterForm() return render(request,'register.html',{'register_form':register_form}) def post(self,request): register_form = RegisterForm(request.POST) if register_form.is_valid(): user_name = request.POST.get('email', None) pass_word = request.POST.get('password', None) # 实例化一个user_profile对象 user_profile = UserProfile() user_profile.username = user_name user_profile.email = user_name user_profile.is_active = False # 对保存到数据库的密码加密 user_profile.password = make_password(pass_word) user_profile.save() send_register_eamil(user_name,'register') return render(request,'login.html') else: return render(request,'register.html',{'register_form':register_form}) views.py
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off"> <input type='hidden' name='csrfmiddlewaretoken' value='gTZljXgnpvxn0fKZ1XkWrM1PrCGSjiCZ' /> <div class="form-group marb20 {% if login_form.errors.email %}errorput{% endif %}"> <label>邮 箱</label> <input type="text" id="id_email" name="email" value="{{ register_form.email.value }}" placeholder="请输入您的邮箱地址" /> </div> <div class="form-group marb8 {% if login_form.errors.password %}errorput{% endif %}"> <label>密 码</label> <input type="password" id="id_password" name="password" value="{{ register_form.password.value }}" placeholder="请输入6-20位非中文字符密码" /> </div> <div class="form-group marb8 captcha1 {% if login_form.errors.captchal %}errorput{% endif %}"> <label>验 证 码</label> {{ register_form.captcha }} </div> <div class="error btns" id="jsEmailTips"> {% for key,error in register_form.errors.items %} {{ error }} {% endfor %} {{ msg }} </div> <div class="auto-box marb8"> </div> <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" /> <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' /> {% csrf_token %} </form>
添加邮件激活的url
# MxOnline/urls.py import xadmin from django.urls import path,include,re_path from django.views.generic import TemplateView from users.views import LoginView,RegisterView,ActiveUserView urlpatterns = [ path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'),name='index'), path('login/',LoginView.as_view(),name = 'login'), path('register/',RegisterView.as_view(),name = 'register'), path('captcha/',include('captcha.urls')), re_path('active/(?P<active_code>.*)/',ActiveUserView.as_view(),name='user_active'), ]