本文共 12627 字,大约阅读时间需要 42 分钟。
项目地址:https://github.com/ylpxzx/Django_Auth
开通阿里云短信服务:https://help.aliyun.com/document_detail/59210.html
开通并审核成功后,可先进入下面链接测试短信服务是否能正常发送
https://api.aliyun.com/new?spm=a2c4g.11186623.2.13.4a7919d9RuZfPg#/
跳转到气泡页
只介绍比较核心的代码部分,其余的可以到上拉取
from django.db import modelsfrom django.contrib.auth.models import AbstractUser# Create your models here.#继承AbstractUser,对原有的User表进行扩展,记得在setting中修改为AUTH_USER_MODEL = 'users.LoginUser'class LoginUser(AbstractUser): ''' 用户表 ''' phone_numbers = models.CharField(verbose_name='手机号', unique=True,max_length=11, default='') def __str__(self): return self.username
扩展了Users表后,需要在Settings.py声明你之后所使用的用户权限表
AUTH_USER_MODEL = 'users.LoginUser' # 扩展系统的用户表后记得添加此行LOGIN_URL = '/login/' # 想进入需要登录才能访问的页面时,如果未登录,将跳转到LOGIN_URL指定的登录界面
采用读取配置文件的方式加载短信发送所需要的字段,解耦。
import configparserimport osfrom aliyunsdkcore.client import AcsClientfrom aliyunsdkcore.request import CommonRequestclass AliYunSms: def __init__(self,phone,params): self.phone = phone self.params = params self.sms_param = parser_config('AliYun') self.SignName = self.sms_param['SignName'] self.TemplateCode = self.sms_param['TemplateCode'] self.client = AcsClient(self.sms_param['ACCESS_KEY_ID'], self.sms_param['ACCESS_KEY_SECRET'], 'cn-hangzhou') def send(self): request = CommonRequest() request.set_accept_format('json') request.set_domain('dysmsapi.aliyuncs.com') request.set_method('POST') request.set_protocol_type('https') # https | http request.set_version('2017-05-25') request.set_action_name('SendSms') request.add_query_param('RegionId', "cn-hangzhou") request.add_query_param('PhoneNumbers', self.phone) # 接收方手机号 request.add_query_param('SignName', self.SignName) # SignName为审核通过的签名名称 request.add_query_param('TemplateCode', self.TemplateCode) # TemplateCode为审核通过的模板code request.add_query_param('TemplateParam', self.params) # 要发送的验证码 response = self.client.do_action_with_exception(request) return response
# 配置redis缓存,短时间存储手机验证码redis_cache = parser_config('Redis')CAHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": redis_cache['LOCATION'], "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # "PASSWORD": "密码", "DECODE_RESPONSES":True } },}
class SendSmsView(View): def get(self,request): return render(request, 'registered.html') def post(self,request): # 处理/static/js/jquery.js的ajax请求:Sendpwd(sender) phone_number = request.POST.get('phone','') print('手机号:',phone_number) if LoginUser.objects.filter(phone_numbers=phone_number): ret = { "status": 40, 'msg': '该手机号已被注册'} return HttpResponse(json.dumps(ret)) else: code = (random.randint(1000, 100000)) # params = "{'code':%d}" % code # 不采用celery方式发送短信 sms_obj = AliYunSms(phone_number,params) print(sms_obj) response = sms_obj.send() # 采用celery发送短信 # send_sms.delay(phone_number,params) cache.set(phone_number, code, 150) # 存入redis ret = { "status": 20, 'msg': '验证码发送成功','code':code} return HttpResponse(json.dumps(ret))
使用ajax请求可以不加载页面发送请求。
实现请求的js文件主要位于以下两个文件处理ajax请求的路由
from django.conf.urls import urlfrom .views import RegisterView,IndexView,SendSmsView,CheckSmsView,PasswordSaveView,LoginView,CheckUserViewapp_name = 'users'urlpatterns = [ url(r'^register/',RegisterView.as_view(),name='register'), url(r'^send_sms/',SendSmsView.as_view()), # 处理static/js/jquery.js的ajax请求,请求事件:Sendpwd url(r'^check_sms/',CheckSmsView.as_view()), # 处理static/js/jquery.step.js的ajax请求,请求事件:$("#applyBtn").click(function(event) url(r'^save_psd/',PasswordSaveView.as_view()), # 处理static/js/jquery.step.js的ajax请求,请求事件:$("#submitBtn").click(function(event) url(r'^login/',LoginView.as_view(),name='login'), url(r'^check_user/',CheckUserView.as_view()), # 处理static/js/jquery.js的ajax请求,请求事件:cliLogin url(r'^index/',IndexView.as_view(),name='index'),]
ajax请求实现,举例:
$("#submitBtn").click(function(event) { var txtconfirm = $.trim($("#confirmpwd").val()); var txtPwd = $("#password").val(); if ($.trim(txtPwd) == "") { Tips('请输入你要设置的密码!'); $("#txtPwd").focus(); return; } if($.trim(txtconfirm) == "") { Tips('请再次输入密码!'); $("#txtconfirm").focus(); return; } if( $.trim(txtconfirm) != $.trim(txtPwd) ) { Tips('你输入的密码不匹配,请从新输入!'); $("#txtconfirm").focus(); return; } $.ajax({ url: "/save_psd/", type: "POST", dataType: "json", data: { 'phone':$("#phone").val(), 'password':$("#confirmpwd").val() }, success: function (data) { console.log('sucess',data) if (data.status == 20){ var yes=step.nextStep(); // 倒计时读秒效果实现 var second = 5; var time = document.getElementById("second"); //定义一个方法,获取span标签,修改span标签体内容,时间-- function showTime(){ second -- ; //判断时间如果<= 0 ,则跳转到首页 if(second <= 0){ //跳转到首页 location.href = "/login/"; } time.innerHTML = second +""; } //设置定时器,1秒执行一次该方法 setInterval(showTime,1000); }else { console.log('密码保存失败') Tip(data.msg); $("#txtPwd").focus(); return; } } }) });
对应视图处理
class PasswordSaveView(View): def get(self,request): return render(request, 'registered.html') def post(self,request): # 处理/static/js/jquery.step.js的ajax请求:$("#submitBtn").click phone_number = request.POST.get('phone','') password = request.POST.get('password','') print('手机号:',phone_number,'密码:',password) if LoginUser.objects.filter(phone_numbers=phone_number): ret = { "status": 40, 'msg': '该手机号已被注册'} return HttpResponse(json.dumps(ret)) else: # 保存注册成功的用户数据 user_profile = LoginUser(phone_numbers=phone_number) user_profile.username = phone_number # user_profile.is_active = False user_profile.password = make_password(password) user_profile.save() ret = { "status": 20, 'msg': '注册成功!'} return HttpResponse(json.dumps(ret))
celery一般用于处理比较耗时的请求任务,而短信、邮箱发送等都属于比较耗时的任务请求,可以接入celery处理。
注意:Celery、Django和Python之间有一定的版本影响 这里采用的各个版本为:Python 3.7celery 4.4.2Django 3.0.6# 安装Celerypip install --upgrade -U celery # 也可自行百度安装方法# 在windows系统下,还需要安装eventletpip install eventlet
from __future__ import absolute_importimport osfrom celery import Celery# 只要是想在自己的脚本中访问Django的数据库等文件就必须配置Django的环境变量os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'login_djangoauth.settings') # login_djangoauth改为自己的项目名# app名字app = Celery('login_djangoauth') # login_djangoauth改为自己的项目名# 配置celeryclass Config: BROKER_URL = 'redis://:密码@127.0.0.1:6379/2' # 记得加上密码,不然会一直报错:RecursionError: maximum recursion depth exceeded in comparison CELERY_RESULT_BACKEND = 'redis://:密码@127.0.0.1:6379/3' # 格式:redis :// [: password@] host [: port] [/ database][? [timeout=timeout[d|h|m|s|ms|us|ns]] [&database=database]]# 无密码的情况:'redis://127.0.0.1:6379/2' CELERY_TIMEZONE = 'Asia/Shanghai' CELERY_ACCEPT_CONTENT = ['json', 'pickle'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json'app.config_from_object(Config)# 到各个APP里自动发现tasks.py文件app.autodiscover_tasks()@app.task(bind=True)def debug_task(self): print('Request: {0!r}'.format(self.request))
from __future__ import absolute_import, unicode_literals# 告诉Django在启动时别忘了检测我的celery文件from .celery import app as celery_app__all__ = ['celery_app']
from celery import shared_taskfrom aliyunsdkcore.client import AcsClientfrom aliyunsdkcore.request import CommonRequestfrom conf.aliyun_api import parser_config# 被@shared_task装饰的为调用的异步请求任务@shared_taskdef send_sms(phone,code): sms_obj = AliYunSms(phone,code) print(sms_obj) sms_obj.send()class AliYunSms: def __init__(self,phone,params): self.phone = phone self.params = params self.sms_param = parser_config('AliYun') self.SignName = self.sms_param['SignName'] self.TemplateCode = self.sms_param['TemplateCode'] self.client = AcsClient(self.sms_param['ACCESS_KEY_ID'], self.sms_param['ACCESS_KEY_SECRET'], 'cn-hangzhou') def send(self): request = CommonRequest() request.set_accept_format('json') request.set_domain('dysmsapi.aliyuncs.com') request.set_method('POST') request.set_protocol_type('https') # https | http request.set_version('2017-05-25') request.set_action_name('SendSms') request.add_query_param('RegionId', "cn-hangzhou") request.add_query_param('PhoneNumbers', self.phone) request.add_query_param('SignName', self.SignName) request.add_query_param('TemplateCode', self.TemplateCode) request.add_query_param('TemplateParam', self.params) response = self.client.do_action_with_exception(request) print(response)
from .tasks import send_smsclass SendSmsView(View): def get(self,request): return render(request, 'registered.html') def post(self,request): # 处理/static/js/jquery.js的ajax请求:Sendpwd(sender) phone_number = request.POST.get('phone','') print('手机号:',phone_number) if LoginUser.objects.filter(phone_numbers=phone_number): ret = { "status": 40, 'msg': '该手机号已被注册'} return HttpResponse(json.dumps(ret)) else: code = (random.randint(1000, 100000)) params = "{'code':%d}" % code # 采用celery异步发送短信 send_sms.delay(phone_number,params) cache.set(phone_number, code, 150) ret = { "status": 20, 'msg': '验证码发送成功','code':code} return HttpResponse(json.dumps(ret))
# login_djangoauth为项目名celery worker -A login_djangoauth --loglevel=info --pool=solo
这里主要介绍个人遇到的一些异常问题,其他情况可自行百度
# login_djangoauth为项目名celery worker -A login_djangoauth --loglevel=info --pool=solo
修改前
def _patch_eventlet(): import eventlet import eventlet.debug eventlet.monkey_patch() blockdetect = float(os.environ.get('EVENTLET_NOBLOCK', 0)) if blockdetect: eventlet.debug.hub_blocking_detection(blockdetect, blockdetect)
修改后
def _patch_eventlet(): import eventlet import eventlet.debug eventlet.monkey_patch(thread=False) # 修改部分 blockdetect = float(os.environ.get('EVENTLET_NOBLOCK', 0)) if blockdetect: eventlet.debug.hub_blocking_detection(blockdetect, blockdetect)
转载地址:http://sgugn.baihongyu.com/