1. 腾讯云短信的注册
大佬的腾讯云短信注册攻略,亲测有用,NBhttps://pythonav.com/wiki/detail/10/81/
2. settings
2.1 安装django-redis
pip3 install django-redis -i https://pypi.douban.com/simple/
2.2 settings配置
# 腾讯云短信
TENCENT_SMS_APPID = xx # 自己应用ID
TENCENT_SMS_APPKEY = "xxxxxxxxxxb27c594587c280" # 自己应用Key
TENCENT_SMS_SIGN = "python后端接口开发" # 签名管理里面的 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
# 模板
TENCENT_SMS_TEMPLATES = {
'register': 993292,
'login': 993155
}
# redis
# 上面是django项目settings中的其他配置....
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.211.55.28:xxx", # 安装redis的主机的 IP 和 端口
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
"PASSWORD": "foobared" # redis密码
}
},
# 提供存储短信验证码
"sms_code": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://106.14.42.253:xxx/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
"PASSWORD": "foobared" # redis密码
}
},
}
3. url
# 手机短信码发送
path('sms/code/', views.SmsCodeAPIView.as_view()),
4. view
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from .serislizer import SmsCodeSerializer
class SmsCodeAPIView(APIView):
"""
发送短信
"""
def post(self, request, *args, **kwargs):
smm_ser_obj = SmsCodeSerializer(data=request.data)
if smm_ser_obj.is_valid():
return Response({'status': 200, "msg": "ok", "data": ""}, status=status.HTTP_200_OK)
return Response({'status': 400, "msg": smm_ser_obj.errors, "data": ""}, status=status.HTTP_400_BAD_REQUEST)
5. serializer
import random
from rest_framework import serializers
from django.conf import settings
from .utils import check_phone
from utils.centent.sms import send_sms_single
from django_redis import get_redis_connection
class SmsCodeSerializer(serializers.Serializer):
"""短信发送序列化器"""
phone = serializers.CharField(max_length=11, min_length=11, write_only=True)
tpl = serializers.CharField()
def validate(self, validate_data):
phone = validate_data.get('phone')
# 进行短信模板id校验
tpl = validate_data.get('tpl')
# tpl
tpl_id = self._get_tpl_id(tpl=tpl)
# 进行手机号格式校验
ret = check_phone(phone=phone)
if ret:
code = self._set_code(phone=phone)
# 都通过发验证码
self._send_sms(phone=phone, tpl_id=tpl_id, code=code)
return validate_data
raise serializers.ValidationError('手机号验证失败')
def _get_tpl_id(self, tpl):
"""
短信模板id的获取
:param tpl: 前端传过来的,login/register/...
:return:
"""
if not tpl:
raise serializers.ValidationError('模板缺失')
tpl_id = settings.TENCENT_SMS_TEMPLATES.get(tpl)
if not tpl_id:
raise serializers.ValidationError('模板错误')
return tpl_id
def _set_code(self, phone):
"""
生成验证码存放redis
:param phone: 手机号
:return:
"""
# 生成code
code = random.randrange(1000, 9999)
print(code)
# 保存redis
conn = get_redis_connection('sms_code')
pipe = conn.pipeline() # 创建管道
pipe.multi() # 开启批量操作 (事务,)
# # 后端倒计时校验 查看redis是否有,有抛异常
init_code = conn.get('init_code_%s' % phone)
if init_code:
raise serializers.ValidationError('一分钟只能发一次')
# 保存正常验证码
pipe.set('sms_code_%s' % phone, code, ex=60 * 5)
# 保存倒计时码
pipe.set('init_code_%s' % phone, code, ex=60)
pipe.execute() # 批量执行了
return code
def _send_sms(self, phone, tpl_id, code):
"""
celery 异步消息队列发送短信
:param phone: 手机号
:param tpl_id: tpl_id 前端传,根据settings里面配置的
:param code: 验证码
:return:
"""
# todo celery异步消息队列
send_sms_single(phone, tpl_id, [code, ])
6. sms(根路径/utils/centent/sms)
# -*- coding:utf-8 -*-
# 腾讯发生短信模块
# pip3 install qcloudsms_py
import ssl
# ssl._create_default_https_context = ssl._create_unverified_context
from qcloudsms_py import SmsMultiSender, SmsSingleSender
from qcloudsms_py.httpclient import HTTPError
from django.conf import settings
def send_sms_single(phone_num, template_id, template_param_list):
"""
单条发送短信
:param phone_num: 手机号
:param template_id: 腾讯云短信模板ID
:param template_param_list: 短信模板所需参数列表,例如:【验证码:{1},描述:{2}】,则传递参数 [888,666]按顺序去格式化模板
:return:
"""
appid = settings.TENCENT_SMS_APPID # 自己应用ID
appkey = settings.TENCENT_SMS_APPKEY # 自己应用Key
sms_sign = settings.TENCENT_SMS_SIGN # 签名管理里面的 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
sender = SmsSingleSender(appid, appkey)
try:
response = sender.send_with_param(86, phone_num, template_id, template_param_list, sign=sms_sign)
except HTTPError as e:
response = {'result': 1000, 'errmsg': "网络异常发送失败"}
return response # 调用
7. utils(app内自己封装的组件)
import re
def check_phone(phone):
"""
手机号校验
:param phone: 手机号
:return: True/None
"""
ret = re.match('^1[3-9][0-9]{9}$', phone)
if ret:
return True
return