Django实战项目-学习任务系统-发送短信通知

发布时间 2023-11-07 11:36:51作者: PandaCode辉

接着上期代码内容,继续完善优化系统功能。

本次增加发送短信通知功能,学习任务系统发布的任务,为了更加及时通知到学生用户,再原有发送邮件通知基础上,再加上手机短信通知功能。

第一步:开通短信通知服务

目前短信通知都是要收费的,本人还没发现免费的短信通知服务,如有网友知道免费资源请分享下。

本人选用的是腾讯云的短信通知服务,一年1千条短信40多元。其他还有阿里云,华为云等等。自己选择实惠好用的平台服务。

 

 

 

1,创建短信签名

创建短信签名这步,目前比较严格了,前提条件,需要实名认证的网站,APP,公众号,小程序等,普通个人开发者要申请下来流程比较繁琐,具体的就不详说了,自己网上查询教程,不是本次重点。

 

 2,创建正文模板

注意按照平台模板格式设置短信内容模板,腾讯云短信模板参数,是按照参数顺序1,2,3等数字来设置的。

 3,等待审核

短信签名和模板提交申请,都要审核,一般10分钟左右,审核不通过,可以修改重新提交申请。

 4,发送短信

短信签名和模板都审批通过了,就可以发送短信,简单测试下效果,平台有验证方式。

国内短信快速入门,参考官方教程:
https://cloud.tencent.com/document/product/382/37745

 

第二步:编写短信通知代码

腾讯云官网短信调用方式有2种:API和SDK方式,不过都不太好用,网上找了一个开源的腾讯短信调用库比较好用。

qcloudsms_py是一个基于Python的,使用腾讯云短信服务的开源库。

1. 安装
在终端中执行以下命令,可以使用 pip 安装 qcloudsms_py:

pip install qcloudsms_py

2. 导入
将 qcloudsms_py 导入项目中:

from qcloudsms_py import SmsSingleSender, SmsMultiSender

3. 发送单条短信

使用 SmsSingleSender 类可以发送单条短信。以下是一个示例代码:

from qcloudsms_py import SmsSingleSender
from qcloudsms_py.httpclient import HTTPError

# 短信应用 SDK AppID
appid = 1412345679  # SDK AppID 以1400开头
# 短信应用 SDK AppKey
appkey = "******************"
# 需要发送短信的手机号码
phone_number = "12345678901"
# 短信模板 ID,需要在短信应用中申请
template_id = 1234  # NOTE: 这里使用的模板 ID 必须已经审核通过
# 短信签名内容,使用 UTF-8 编码,必须填写已审核通过的签名
sms_sign = "腾讯云"

try:
    ssender = SmsSingleSender(appid, appkey)
    # 指定模板单发
    result = ssender.send_with_param(phone_number, template_id, ["123456"], sign=sms_sign)
    print(result)

except HTTPError as e:
    print(e)

except Exception as e:
    print(e)

 

 

 

第三步:短信通知整合到学习系统中

1,编写短信发送工具方法

./mysite/study_system/smsutil.py

 

# -*- coding: utf-8 -*-

from qcloudsms_py import SmsMultiSender, SmsSingleSender
from qcloudsms_py.httpclient import HTTPError

'''=================================================
短信通知工具

腾讯云短信通知服务
发送频率限制
设置
对同一个手机号,30秒 内发送短信条数不超过1条
对同一个手机号,1小时内发送短信条数不超过5条
对同一个手机号,1 自然日内发送短信条数不超过10条

变量参数长度限制: 0-12个字符
=================================================='''


def send_sms_single(phone_num, template_id, template_param_list):
    '''
    @方法名称: 单条发送短信
    @中文注释: 单条发送短信
    @入参:
        @param phone_num str 手机号
        @param template_id int 腾讯云短信模板ID
        @param template_param_list list 短信模版参数列表
    @出参:
        @返回状态:
            @return 0 失败
            @return 1 成功
        @返回错误码
        @返回错误信息
    @作    者: PandaCode辉
    @weixin公众号: PandaCode辉
    @创建时间: 2023-11-02
    @使用范例: send_sms_single('15023456789', 1234567, [12345, 567])
    短信模板所需参数列表,例如:【验证码:{1},描述:{2}】,则传递参数 [888,666]按顺序去格式化模板
    '''
    try:

        if (not type(phone_num) is str):
            return [0, "F00001", "手机号参数类型错误,不为字符串", [None]]
        if (not type(template_id) is int):
            return [0, "F00001", "腾讯云短信模板ID类型错误,不为整数", [None]]
        if (not type(template_param_list) is list):
            return [0, "F00001", "短信模版参数列表类型错误,不为列表", [None]]

        # 自己应用ID
        appid = 123456789
        # 自己应用Key
        appkey = '******************'

        # 新建单条短信发送实例对象
        sender = SmsSingleSender(appid, appkey)

        # 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
        sms_sign = '签名内容'

        response = sender.send_with_param(86, phone_num, template_id, template_param_list, sign=sms_sign)

        return [1, '000000', "单条短信发送成功", [response]]
    except HTTPError as e:
        return [0, '999999', "单条短信发送异常,网络异常发送失败" + str(e), [None]]


def send_sms_multi(phone_num_list, template_id, template_param_list):
    '''
    @方法名称: 批量发送短信
    @中文注释: 批量发送短信
    @入参:
        @param phone_num_list list 手机号列表
        @param template_id int 腾讯云短信模板ID
        @param template_param_list list 短信模版参数列表
    @出参:
        @返回状态:
            @return 0 失败
            @return 1 成功
        @返回错误码
        @返回错误信息
    @作    者: PandaCode辉
    @weixin公众号: PandaCode辉
    @创建时间: 2023-11-02
    @使用范例: send_sms_multi(['15123456789','15123456789'], 1234567, [12345, 567])
    短信模板所需参数列表,例如:【验证码:{1},描述:{2}】,则传递参数 [888,666]按顺序去格式化模板
    '''
    try:

        if (not type(phone_num_list) is list):
            return [0, "F00001", "手机号列表参数类型错误,不为列表", [None]]
        if (not type(template_id) is int):
            return [0, "F00001", "腾讯云短信模板ID类型错误,不为整数", [None]]
        if (not type(template_param_list) is list):
            return [0, "F00001", "短信模版参数列表类型错误,不为列表", [None]]

        # 自己应用ID
        appid = 123456789
        # 自己应用Key
        appkey = '******************'

        # 新建多条短信发送实例对象
        sender = SmsMultiSender(appid, appkey)

        # 自己腾讯云创建签名时填写的签名内容(使用公众号的话这个值一般是公众号全称或简称)
        sms_sign = '签名内容'

        response = sender.send_with_param(86, phone_num_list, template_id, template_param_list, sign=sms_sign)

        return [1, '000000', "批量短信发送成功", [response]]
    except HTTPError as e:
        return [0, '999999', "批量短信发送异常,网络异常发送失败" + str(e), [None]]


# 主方法
if __name__ == '__main__':
    phone_num = '15123456789'
    template_id = 1234567
    # 模板参数列表:学习系统新任务:{1}; 任务内容:{2}; 完成时间:{3}; 奖励积分:{4}; 请及时处理。
    # 变量参数长度限制: 0-12个字符
    template_param_list = ['每天晚上学习英语新闻', '每晚阅读英语新闻30分钟', '1天', '10']
    # 单条发送短信
    rst = send_sms_single(phone_num, template_id, template_param_list)
    print(rst)

    phone_num_list = ['15123456789', '15123456789']
    template_id = 1234567
    # 模板参数列表:学习系统新任务:{1}; 任务内容:{2}; 完成时间:{3}; 奖励积分:{4}; 请及时处理。
    # 变量参数长度限制: 0-12个字符
    template_param_list = ['每天早上背英语单词', '每天背英语单词30个', '1天', '10']
    # 批量发送短信
    rst = send_sms_multi(phone_num_list, template_id, template_param_list)
    print(rst)

 

2,更新定时任务实现方法

 ./mysite/study_system/utils.py:

def study_sys_pub_day_task():
    '''
    @方法名称: 定时发布学习系统的定时任务,同时邮件通知,同时发短信通知
    @中文注释: 定时发布学习系统的定时任务,同时邮件通知,同时发短信通知
    @入参:
    @出参:
        @返回状态:
            @return 0 失败,数据库异常
            @return 1 成功
        @返回错误码
        @返回错误信息
    @作    者: PandaCode辉
    @weixin公众号: PandaCode辉
    @创建时间: 2023-08-28
    '''
    try:

        # 查询全部待发布定时日常任务列表
        studyScheduledTaskList = StudyScheduledTask.objects.all()

        # 查询是否成功
        if len(studyScheduledTaskList) > 0:
            # 循环发布定时任务
            for scheduledTask in studyScheduledTaskList:
                # 定时任务参数信息
                scheduled_id = str(scheduledTask.scheduled_id)
                schedule_type = scheduledTask.schedule_type
                task_title = scheduledTask.task_title
                task_description = scheduledTask.task_description
                deadline_days = str(scheduledTask.deadline_days)
                reward_points = str(scheduledTask.reward_points)
                user_id = scheduledTask.created_by
                task_type = str(scheduledTask.task_type)
                exp_daytime = str(scheduledTask.schedule_time)
                pub_daytime = str(scheduledTask.pub_daytime)
                phone_num = scheduledTask.phone_num

                # 今天
                # UTC格式当前时区时间
                t = time.localtime()
                now_daytime = str(time.strftime("%Y%m%d%H%M%S", t))
                # print('当前日期时间:' + now_daytime)

                now_day = now_daytime[:8]
                print('当前日期:' + now_day)
                # 每天一次,判断当天是否已经发布任务?
                if (pub_daytime == now_day):
                    print('当天已经发布任务,不用再发.')
                    continue

                # 根据循环周期判断
                if schedule_type == 'day-1':
                    exp_daytime = now_day + exp_daytime + '00'
                    # print(exp_daytime)
                    exp_daytime = re.sub(r'\D', "", exp_daytime)
                    # print('预定日期时间:' + exp_daytime)

                    # 计算日期差值
                    dis = time_diff(now_daytime, exp_daytime, "minutes")
                    # print(dis[3][0])

                    # 计算时间差值
                    dis_min = int(dis[3][0])
                    # print(dis_min)
                    # 再判断当前时间是否处于预定时间区间内?
                    # 比如 08:30,当前时间08:27或08:33查到都算预定时间区间,前后相差10分钟作为判断区间。
                    if dis_min <= 10:
                        print('处于预定时间区间内,开始发布定时任务.')

                        # 今天
                        # UTC格式当前时区时间
                        t = time.localtime()
                        work_date = time.strftime("%Y-%m-%d %H:%M:%S", t)
                        # print('当前日期时间:' + str(work_date))

                        actual_days = 0
                        task_status = 0
                        # 获取当前用户对象
                        cur_user = user_id

                        # 创建对象并保存到数据库
                        study_task = StudyTask(task_title=task_title, task_type=task_type,
                                               task_description=task_description,
                                               reward_points=reward_points, deadline_days=deadline_days,
                                               task_status=task_status,
                                               actual_days=actual_days, created_by=cur_user,
                                               created_time=work_date,
                                               update_time=work_date)
                        # 保存到数据库是否成功
                        study_task.save()

                        # 发布成功后,再更新定时任务表日期字段 pub_daytime
                        # 根据ID查询对象数据
                        scheduledTask2 = StudyScheduledTask.objects.filter(scheduled_id=scheduled_id)
                        # 更新定时任务表,发布日期
                        scheduledTask2.update(pub_daytime=now_day)
                        print('更新定时任务表,发布日期,成功')

                        # 邮件通知,接收邮箱
                        receiver_mail = cur_user.email
                        # 发邮件通知
                        # 邮件主题
                        subject = '【学习系统新任务:' + task_title + ''
                        # 邮件内容
                        content = ''
                        # 邮件内容换行符,'plain'纯文本格式邮件时候用\n或者\r字符串换行符
                        # HTML格式,使用<br>换行符
                        content += '【任务ID :' + str(study_task.task_id) + '' + '\n'
                        content += '【发布时间 :' + work_date + '' + '\n'
                        content += '【任务名称 :' + task_title + '' + '\n'
                        # 任务类型
                        if task_type == 1:
                            # color : blue
                            content += '【任务类型 :1-系统任务】' + '\n'
                        elif task_type == 2:
                            content += '【任务类型 :2-辅导员任务】' + '\n'
                        elif task_type == 4:
                            content += '【任务类型 :4-自学任务】' + '\n'

                        content += '【任务内容说明 :' + task_description + '' + '\n'
                        content += '【计划完成天数 :' + str(deadline_days) + ' 天】' + '\n'
                        content += '【任务奖励 :' + str(reward_points) + '点】' + '\n'
                        content += '================================='
                        # 发送邮件
                        rstmail = send_qq_mail(subject, content, receiver_mail)
                        print('发送邮件成功')

                        # 再发送短信通知
                        # 短信通知,接收手机号码,如果定时任务没有指定手机号码,则不发短信通知
                        if phone_num == '':
                            continue
                        # 腾讯云短信模板ID
                        template_id = 1234567
                        # 模板参数列表:学习系统新任务:{1}; 任务内容:{2}; 完成时间:{3}; 奖励积分:{4}; 请及时处理。
                        # 变量参数长度限制: 0-12个字符
                        template_param_list = [task_title, task_title, str(deadline_days) + '',
                                               str(reward_points)]
                        # 单条发送短信
                        rst = send_sms_single(phone_num, template_id, template_param_list)
                        print(rst)
                        print('发送短信通知成功')
                    else:
                        print('不处于预定时间区间内,不用处理.')
                        pass
                elif (schedule_type == 'timing'):
                    # 定时一次,判断当前时间是否处于预定日期 + 时间区间内?
                    exp_daytime = re.sub(r'\D', "", exp_daytime) + '00'
                    # print('预定日期时间:' + exp_daytime)
                    # 计算日期差值
                    dis = time_diff(now_daytime, exp_daytime, "minutes")
                    # print(dis[3][0])

                    # 计算时间差值
                    dis_min = int(dis[3][0])
                    # print(dis_min)
                    # 再判断当前时间是否处于预定时间区间内?
                    # 比如 08:30,当前时间08:27或08:33查到都算预定时间区间,前后相差10分钟作为判断区间。
                    if dis_min <= 10:
                        print('处于预定时间区间内,开始发布定时任务.')

                        # 今天
                        # UTC格式当前时区时间
                        t = time.localtime()
                        work_date = time.strftime("%Y-%m-%d %H:%M:%S", t)
                        # print('当前日期时间:' + str(work_date))

                        actual_days = 0
                        task_status = 0
                        # 获取当前用户对象
                        cur_user = user_id

                        # 创建对象并保存到数据库
                        study_task = StudyTask(task_title=task_title, task_type=task_type,
                                               task_description=task_description,
                                               reward_points=reward_points, deadline_days=deadline_days,
                                               task_status=task_status,
                                               actual_days=actual_days, created_by=cur_user,
                                               created_time=work_date,
                                               update_time=work_date)
                        # 保存到数据库是否成功
                        study_task.save()

                        receiver_mail = cur_user.email
                        # 发邮件通知
                        # 邮件主题
                        subject = '【学习系统新任务:' + task_title + ''
                        # 邮件内容
                        content = ''
                        # 邮件内容换行符,'plain'纯文本格式邮件时候用\n或者\r字符串换行符
                        # HTML格式,使用<br>换行符
                        content += '【任务ID :' + str(study_task.task_id) + '' + '\n'
                        content += '【发布时间 :' + work_date + '' + '\n'
                        content += '【任务名称 :' + task_title + '' + '\n'
                        # 任务类型
                        if task_type == 1:
                            # color : blue
                            content += '【任务类型 :1-系统任务】' + '\n'
                        elif task_type == 2:
                            content += '【任务类型 :2-辅导员任务】' + '\n'
                        elif task_type == 4:
                            content += '【任务类型 :4-自学任务】' + '\n'

                        content += '【任务内容说明 :' + task_description + '' + '\n'
                        content += '【计划完成天数 :' + str(deadline_days) + ' 天】' + '\n'
                        content += '【任务奖励 :' + str(reward_points) + '点】' + '\n'
                        content += '================================='
                        # 发送邮件
                        rstmail = send_qq_mail(subject, content, receiver_mail)

                        # 再发送短信通知
                        # 短信通知,接收手机号码,如果定时任务没有指定手机号码,则不发短信通知
                        if phone_num == '':
                            continue
                        # phone_num = cur_user.phone_num
                        # 腾讯云短信模板ID
                        template_id = 1234567
                        # 模板参数列表:学习系统新任务:{1}; 任务内容:{2}; 完成时间:{3}; 奖励积分:{4}; 请及时处理。
                        # 变量参数长度限制: 0-12个字符
                        template_param_list = [task_title, task_title, str(deadline_days) + '',
                                               str(reward_points)]
                        # 单条发送短信
                        rst = send_sms_single(phone_num, template_id, template_param_list)
                        print(rst)
                        print('发送短信通知成功')

                        # 发布成功后,再删除定时任务表数据,1次性任务
                        if rstmail[0] == 1:
                            # 发布完就自动删除任务配置。
                            scheduledTask.delete()
                            print('发布完就自动删除任务配置,完成。')
                    else:
                        print('不处于预定时间区间内,不用处理.')
                        pass
                else:
                    # 每周几一次,判断当天是否已经发布任务?再判断当前时间是否处于预定时间区间内?
                    week_int = datetime.now().weekday() + 1
                    # print('今天周:' + str(week_int))
                    week_str = 'week-' + str(week_int)
                    # print('今天周:' + week_str)
                    # 先判断当天是否预定周几
                    if week_str == schedule_type:
                        # 然后再判断当前时间是否处于预定时间区间内?
                        exp_daytime = now_day + exp_daytime + '00'
                        # print(exp_daytime)
                        exp_daytime = re.sub(r'\D', "", exp_daytime)
                        # print('预定日期时间:' + exp_daytime)

                        # 计算日期差值
                        dis = time_diff(now_daytime, exp_daytime, "minutes")
                        # print(dis[3][0])

                        # 计算时间差值
                        dis_min = int(dis[3][0])
                        # print(dis_min)
                        # 再判断当前时间是否处于预定时间区间内?
                        # 比如 08:30,当前时间08:27或08:33查到都算预定时间区间,前后相差10分钟作为判断区间。
                        if dis_min <= 10:
                            print('处于预定时间区间内,开始发布定时任务.')

                            # 今天
                            # UTC格式当前时区时间
                            t = time.localtime()
                            work_date = time.strftime("%Y-%m-%d %H:%M:%S", t)
                            # print('当前日期时间:' + str(work_date))

                            actual_days = 0
                            task_status = 0
                            # 获取当前用户对象
                            cur_user = user_id

                            # 创建对象并保存到数据库
                            study_task = StudyTask(task_title=task_title, task_type=task_type,
                                                   task_description=task_description,
                                                   reward_points=reward_points, deadline_days=deadline_days,
                                                   task_status=task_status,
                                                   actual_days=actual_days, created_by=cur_user,
                                                   created_time=work_date,
                                                   update_time=work_date)
                            # 保存到数据库是否成功
                            study_task.save()

                            # 发布成功后,再更新定时任务表日期字段 pub_daytime
                            # 根据ID查询对象数据
                            scheduledTask2 = StudyScheduledTask.objects.filter(scheduled_id=scheduled_id)
                            # 更新定时任务表,发布日期
                            scheduledTask2.update(pub_daytime=now_day)
                            print('更新定时任务表,发布日期,成功')

                            receiver_mail = cur_user.email
                            # 发邮件通知
                            # 邮件主题
                            subject = '【学习系统新任务:' + task_title + ''
                            # 邮件内容
                            content = ''
                            # 邮件内容换行符,'plain'纯文本格式邮件时候用\n或者\r字符串换行符
                            # HTML格式,使用<br>换行符
                            content += '【任务ID :' + str(study_task.task_id) + '' + '\n'
                            content += '【发布时间 :' + work_date + '' + '\n'
                            content += '【任务名称 :' + task_title + '' + '\n'
                            # 任务类型
                            if task_type == 1:
                                # color : blue
                                content += '【任务类型 :1-系统任务】' + '\n'
                            elif task_type == 2:
                                content += '【任务类型 :2-辅导员任务】' + '\n'
                            elif task_type == 4:
                                content += '【任务类型 :4-自学任务】' + '\n'

                            content += '【任务内容说明 :' + task_description + '' + '\n'
                            content += '【计划完成天数 :' + str(deadline_days) + ' 天】' + '\n'
                            content += '【任务奖励 :' + str(reward_points) + '点】' + '\n'
                            content += '================================='
                            # 发送邮件
                            rstmail = send_qq_mail(subject, content, receiver_mail)
                            print('发送邮件成功')

                            # 再发送短信通知
                            # 短信通知,接收手机号码,如果定时任务没有指定手机号码,则不发短信通知
                            if phone_num == '':
                                continue
                            # phone_num = cur_user.phone_num
                            # 腾讯云短信模板ID
                            template_id = 1234567
                            # 模板参数列表:学习系统新任务:{1}; 任务内容:{2}; 完成时间:{3}; 奖励积分:{4}; 请及时处理。
                            # 变量参数长度限制: 0-12个字符
                            template_param_list = [task_title, task_title, str(deadline_days) + '',
                                                   str(reward_points)]
                            # 单条发送短信
                            rst = send_sms_single(phone_num, template_id, template_param_list)
                            print(rst)
                            print('发送短信通知成功')

                        else:
                            print('不处于预定时间区间内,不用处理.')
                            pass
                    else:
                        print('当天不是预定周几,不用处理.')
                        pass
                print('========================')
                # 休眠2秒
                time.sleep(2)
            print('循环发布结束成功.')
        else:
            print('查询失败')

        return [1, '000000', "循环发布结束成功", [None]]

    except Exception as e:
        return [0, '999999', "定时发布学习系统的日常任务,同时邮件通知异常," + str(e), [None]]

 

第三步:运行测试效果

1,定时发布学习任务

 -------------------------------------------------end -------------------------------------------------