django+小程序发送模板消息

846 阅读4分钟

在做小程序的时候需要发送服务消息提醒,使用到了小程序模板消息发送,现记录下开发过程。

access_token

使用模板消息需要使用到access_token,access_token的有效期是7200秒(两小时),在有效期内,可以一直使用,只有当access_token过期时,才需要再次调用接口获取access_token。

获取access_token接口的调用频率限制为2000次/天,在实际应用中,我们可以将获取到的access_token存储起来,然后定期调用access_token接口更新它,以保证随时取出的access_token都是有效的。

access_token的保存

在本项目中,我是将获取的token存储在数据库中,使用定时任务,每1小时40分钟更新一次,获取新的token更新存储在数据库中,前端如果需要,后端就通过接口返回给前端使用。

首先新建数据模型,存储access_token,如下所示:

class AppItem(models.Model):
    Appid = models.CharField(max_length=128, blank=True, null=True, verbose_name='APPID')  #appid 
    expires_in = models.CharField(max_length=128, blank=True, null=True, verbose_name='expires_in')  #过期时间
    Token = models.CharField(max_length=255,  unique=True, blank=True, null=True, verbose_name='token', db_index=True) #access_token 这里要注意长度,太短存储会失败 token官方给出的长度是512个字符空间

    class Meta:
        verbose_name = '小程序token信息'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.Appid

定时任务获取更新access_token

在django中我使用了django-crontab模块制作定时任务,

安装django-crontab模块:

pip install django-crontab

配置(settings.py):

INSTALLED_APPS = [
    ...
    'django_crontab',
    ...
]
#设置定时任务
CRONJOBS  = [
    ('40 */1 * * *', 'activity.crontab_task.update_token', '>> /home/taskcrontab/task_crontab.log')
]
# 每小时的40分钟执行一次
#  分钟 小时 

使用django-crontab需要开启本机的crontab定时任务,否则无法生效。django-crontab具体的设置参数可以查看文档

新建crontab_task.py定时任务文件,如下所示

import requests
from activity.models import *
def update_token():
    appid = 'appid'
    secret = 'secret'

    url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s' % (appid, secret)
    dict_data = requests.get(url)
    token = dict_data.json()['access_token']
    expires_in = dict_data.json()['expires_in']
    
    appitem = AppItem.objects.get(id = 1)
    appitem.Token = token
    appitem.expires_in = expires_in
    appitem.save()
# dajango-crontab任务使用方法
python manage.py crontab add #新增定时任务
python manage.py crontab show # 查看定时任务
# 修改定时任务需要重新add启动
# 启动成功后,运行python manage.py crontab show命令即可查询当前系统下的定时任务,显示如下:
Currently active jobs in crontab:
0ddad8dd56d2ff42252985ff2cc11edd -> ('40 */1 * * *', 'activity.crontab_task.update_token', '>> /home/taskcrontab/task_crontab.log')

#执行后查看/home/taskcrontab/task_crontab.log日志可看到执行的日志

后端模板发送

现在我们已经能够正确获取access_token,且保证数据库中的都是正确且有效的token,然后我们据可以参照官方文档,发送模板信息了。

1、获取模板ID

有两种方式可以获取模板ID

  • (1)通过模版消息管理接口获取模版ID(详见服务端==>模版消息模块)
  • (2)在微信公众平台手动配置获取模版ID(我的模板==>点击详情==>点击复制或手动复制写入代码中)

img

2、调用接口下发模板消息

我使用https方式调用,调用地址为POST api.weixin.qq.com/cgi-bin/mes…

具体调用方法如下:

class Send_Message(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    def post(self, request):
        form_id = request.data.get('form_id')
        to_url = request.data.get('to_url')
        title = request.data.get('title')
        brief = request.data.get('brief')
        begintime = request.data.get('begintime')
        access_token = AppItem.objects.get(id = 1).Token
        url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + access_token
        user = request.user #获取当前用户
        postData = {
            "touser": user.username,
            "template_id": "template_id",   #此处更换成正式的模板id从模板库中可以查看
            "page": to_url,
            "form_id": form_id,
            "data": {
                "keyword1": {
                    "value": title
                },
                "keyword2": {
                    "value": brief
                },
                "keyword3": {
                    "value": begintime
                }
            },
        }
        res = requests.post(url,data=json.dumps(postData))
        res = res.json()
        return DaoJsonResponse(res,'0','success')

前端获取formId,并发送消息

模板消息不能根据自己的想法任意发送,需要使用一个触发性事件;比如表单提交(获取formid)、支付(获取prepay_id),我这边只需要表单提交即可

1、首先需要对我的

组件进行发模板消息的声明,即设置属性 report-submit="true"

<form bindsubmit='joinActivity' report-submit='true'>
    <view class="acti-join"><button formType="submit">参加</button></view>
</form>

2、在对应的js文件中,增加提交代码:

joinActivity(e) {
    let formId = e.detail.formId;
    if ('the formId is a mock one' == formId) {
        return;
    }
    this.sendMessage(formId); //发送信息
}

3、调取发送消息的接口,传入具体模板消息字段:

/**发送模板消息 */
sendMessage(formid) {
    return requestPromise({
        url: API.sendMessage,
        method: 'post',
        header: app.globalData.header,
        data: {
            "form_id": formid,
            "to_url": `pages/detail/detail?activity_id=${this.data.activity_id}`,
            "title": this.data.detailData.title,
            "brief": this.data.detailData.content
        }
    }).then(res => {
        console.log('发送成功')
    }).catch(error => {
        console.log(error)
    })
},

在本地的开发工具中,获取的formId一律是**"the formId is a mock one"**,要想看到具体的消息,需使用手机测试

总结

模板消息的发送官方文档都写的很清楚,目前做的都是触发式发送信息,拿到formID直接调取接口发送,后期会考虑将formID暂存,在过期时间内按照需要去调取,发送需要的消息。