前后端分离djangorestframework—— 接入微信模板消息推送
微信
什么是微信也不多说,跟前面的支付宝一样的
微信支付
微信支付也有个沙箱环境,沙箱环境官方文档

由文档中那句很显眼的话所得,即使是测试环境也需要真实的商户号,所以这个就没法想支付宝那样用沙箱账号来演示了。至于为什么没有沙箱账号这就不得而知了,想接入微信支付商户的朋友,请移步先注册为商户,上传相关资料审核后方可使用:传送门
所以关于微信支付,由于这些种种限制,就不去注册商户了,所以支付方面本文在此略过,感兴趣的朋友自己去研究了,我看微信的文档也很浅显易懂的
微信模板消息推送
因为微信的模板消息推送改版,现在需要认证的微信企业号才能玩,所以目前来说我们只能使用微信给的沙箱测试平台了,传送门
用你的微信登录,之后会给我们自动生成一个id 和key:

还有一个测试的可用公众账号:

接着按微信官方给的文档:模板消息推送
其实大概的流程就是这样:

1.默认情况下,用户的微信只和微信服务端有联系,且微信服务端里有用户的唯一ID,而我们的平台的目标是要通过公众号给用户发消息
2.但是默认用户的微信和我们平台的微信不相通的,如隔了一道墙
3.我们给用户一个页面,页面上有我们的二维码,让用户扫码关注我们的公众号
4.在第3步操作也是通过微信的服务端作为中间人完成的,且当用户关注成功的同时,微信服务端会把用户ID自动回传(或者说回调)给我们平台的公众号
5.拿到用户ID之后,我们的微信公众号就可以给用户推送消息了
其实步骤是挺简单的,上面5步中,其实实际的业务逻辑只有第3,第4和第5三个步骤,且这几个步骤里每个的请求url都需要通过微信服务端来完成,所以还需要再看下微信的官方文档给我们解说的
前期准备:
1,修改地址:
还是刚才那个申请测试账号页面,滑动下面,找到网页账号这里,点修改

看到的提示,写得很清楚,我这里只是作为测试而已,这个地址不能是127.0.0.1换回地址了,至少得是局域网地址,因为一会儿用手机微信测试时需要调用这个地址,所以你的手机得和电脑是同一个局域网段,当然真实的使用时是公网的地址

点击确认之后,显示通过安全检测的话就配置成功了

2.还要创建一个模板,获取一个模板id
点新增测试模板:添加模板时注意格式,比如下面的{{first.DATA}},这个【.DATA】才是我们需要添加的数据,其他都不是,就好比Python中的字符串格式化一样,做类比理解就很能懂了

按照文档给的提示操作就行,提交之后如下,所以你如果填错了,只能删除重新添加,不能修改

3.作为接收信息的用户微信号必须关注测试账号:

4.如果有需要的话,设置js的sdk url
当然是要调用微信的sdk时才会用到这个

代码实现
前面的准备工作准备好之后,开始写代码
不过,先通过微信的文档,得知我们此时需要用的url:
1.绑定url:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
相关参数:
|
参数 |
必须 |
说明 |
|
appid |
是 |
公众号的唯一标识(这个就是我们前面申请的) |
|
redirect_uri |
是 |
授权后重定向的回调链接地址(我们前面申请的) |
|
response_type |
是 |
返回类型,请填写code |
|
scope |
是 |
应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息) |
|
state |
否 |
重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节,该值会被微信原样返回,我们可以将其进行比对,防止别人的攻击。 |
|
#wechat_redirect |
否 |
直接在微信打开链接,可以不填此参数。做页面302重定向时候,必须带此参数 |
2.获取token的url
https://api.weixin.qq.com/sns/oauth2/access_token
相关参数:
|
appid |
您的测试id号 |
|
secret |
您的测试id的secret |
|
code |
微信自动回传的参数,用request.GET.get("code")获取 |
|
grant_type |
authorization_code |
3.发送模板消息的接口
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN


4.发送非模板,正文消息的url
https://api.weixin.qq.com/cgi-bin/message/custom/send
相关参数跟模板消息的参数一样
真正的代码实现
好的,开始码代码,干!
创建一个名为WachatTest的django项目,app名就是app:

然后因为要生成二维码,此处运用了qrcode.js的第三方js库 文件下载:点我
根目录创建static目录,存放如下文件,wx.jpg就是刚才那个测试微信公众号的图片,我把它下载下来并更名为wx.jpg了

url:

html:

settings:

还是配置文件部分,如果你启动项目时提示ALLOW_HOSTS之类的错误,作如下更改:

views:




与模板相关的配置,注意与之前创建的模板对应


model,db_index=True的意思是自动在数据创建索引的意思

运行项目之前记得迁移数据库,并写入几个数据作为测试
启动项目,登录再关注,不多说

登录成功之后,绑定页面,点击按钮之后,把这个测试的公众号二维码图片转成了带有一些参数的url,然后qrcode把这个带有参数的url转成了二维码:

我用一个微信号测试扫码之后(前提必须先关注那个微信公众测试号才能授权),点击允许

然后会跳转到这个界面,表示成功授权

现在再做最终的模板消息发送,访问/sendmsg:

查看手机端信息,得到的信息正好是我们之前设置的

大概的流程就走完了,因为我只是测试,没有做得多么高大上,其实比如那个模板消息,可以根据不同的用户发不同的数据,或者这段数据直接搞一个form表单,让非开发人员也可以使用它,点击发送就行了,还有上面说的那个当前用户的问题,只给当前用户发,不给没有操作的人发,或者定向群发啥啥的,反正主要的开发逻辑就这些,其他的随便玩,玩出花来都可以
微信官方的全部流程:传送门
相关的代码:
import hashlib
from django.db import models
class UserInfo(models.Model):
username = models.CharField("用户名", max_length=64, unique=True)
password = models.CharField("密码", max_length=64)
uid = models.CharField(verbose_name='个人唯一ID', max_length=64, unique=True)
wx_id = models.CharField(verbose_name="微信ID", max_length=128, blank=True, null=True, db_index=True)
def save(self, *args, **kwargs):
# 创建用户时,为用户自动生成个人唯一ID
if not self.pk:
m = hashlib.md5()
m.update(self.username.encode(encoding="utf-8"))
self.uid = m.hexdigest()
super(UserInfo, self).save(*args, **kwargs)
models
from django.contrib import admin
from django.urls import path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('bind/', views.bind),
path('bind_qrcode/', views.bindQrcode),
path('callback/', views.callback),
path('sendmsg/', views.sendmsg)
]
urls
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from django.conf import settings
import requests
from app import models
import json
# Create your views here.
def login(request):
"""
用户登录
:param request:
:return:
"""
# models.UserInfo.objects.create(username='luffy',password=123)
if request.method == "POST":
user = request.POST.get('user')
pwd = request.POST.get('pwd')
obj = models.UserInfo.objects.filter(username=user, password=pwd).first()
if obj:
request.session['user_info'] = {'id': obj.id, 'name': obj.username, 'uid': obj.uid}
return redirect('/bind/')
else:
return render(request, 'login.html')
def bind(request):
"""用户绑定页面"""
return render(request, 'auth.html')
def bindQrcode(request):
"""生成二维码"""
ret = {'code': 1000}
try:
access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"
access_url = access_url.format(
appid=settings.WECHAT_CONFIG["app_id"],
redirect_uri=settings.WECHAT_CONFIG["redirect_uri"],
state=request.session['user_info']['uid']
)
ret['data'] = access_url
except Exception as e:
ret['code'] = 1001
ret['msg'] = str(e)
return JsonResponse(ret)
def callback(request):
"""
用户在手机微信上扫码后,微信自动调用该方法。
用于获取扫码用户的唯一ID,以后用于给他推送消息。
:param request:
:return:
"""
code = request.GET.get("code")
# 用户UID
state = request.GET.get("state")
# 获取该用户openId(用户唯一,用于给用户发送消息)
res = requests.get(
url="https://api.weixin.qq.com/sns/oauth2/access_token",
params={
"appid": settings.WECHAT_CONFIG["app_id"],
"secret": settings.WECHAT_CONFIG["appsecret"],
"code": code,
"grant_type": 'authorization_code',
}
).json()
# 获取的到openid表示用户授权成功
openid = res.get("openid")
if openid:
models.UserInfo.objects.filter(uid=state).update(wx_id=openid)
response = "<h1>授权成功 %s </h1>" % openid
else:
response = "<h1>用户扫码之后,手机上的提示</h1>"
return HttpResponse(response)
def get_access_token():
"""获取token"""
result = requests.get(
url='https://api.weixin.qq.com/cgi-bin/token',
params={
"grant_type": "client_credential",
"appid": settings.WECHAT_CONFIG['app_id'],
"secret": settings.WECHAT_CONFIG['appsecret'],
}
).json()
if result.get('access_token'):
access_token = result.get('access_token')
else:
access_token = None
return access_token
def send_content_msg(user_id, access_token):
"""内容消息发送"""
body = {
'touser': user_id,
'msgtype': 'text',
'text': {
'content': '内容。。。。。不是模板消息'
}
}
response = requests.post(
url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
params={
'access_token': access_token
},
data=bytes(json.dumps(body, ensure_ascii=False), encoding='utf-8')
)
result = response.json()
return result
def send_template_msg(user_id, access_token):
"""模板消息发送"""
result = requests.post(
url='https://api.weixin.qq.com/cgi-bin/message/template/send',
params={
'access_token': access_token
},
json={
"touser": user_id,
"template_id": settings.WECHAT_CONFIG['template_id'],
"data": {
"first": {
"value": "微信模板页面发送消息",
"color": "#173177"
},
"kw1": {
"value": "卧槽调这个参数搞了有点久",
"color":"#173177"
},
"kw2": {
"value": "可不是咋地"
},
"kw3": {
"value": "就看这次能不能成功了"
},
}
}
)
result = result.json()
return result
def sendmsg(requet):
access_token = get_access_token()
# 这里由于我本来就只有一个数据,所以直接写死了,真实的开发当然是用当前登录用户扫码关注的用户对应
userobj = models.UserInfo.objects.filter(id=1).first()
# 发送模板消息
result = send_template_msg(userobj.wx_id, access_token)
# 发送正文消息
# result = send_content_msg(userobj.wx_id, access_token)
if result.get('errcode') == 0:
return HttpResponse('发送成功')
return HttpResponse('发送失败')
views
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户授权</title>
<script src="{% static "js/jquery.min.js" %}"></script>
<script src="{% static "js/jquery.qrcode.min.js" %}"></script>
<script src="{% static "js/qrcode.js" %}"></script>
</head>
<body>
<input onclick="userauth() " type="button" value="关注我们有惊喜哦">
<div>
<img style="height: 100px;width: 100px" src="{% static 'img/wx.jpg' %}">
</div>
<div id="qrcode" style="width: 250px;height: 250px;background-color: white;margin: 100px auto;"></div>
<script type="text/javascript">
function userauth() {
$.ajax({
url: '/bind_qrcode/',
type: 'GET',
success: function (data) {
console.log(data);
$('#qrcode').empty().qrcode({text: data.data});
}
});
}
</script>
</body>
</html>
html:auth.html
ALLOWED_HOSTS = ['192.168.0.8']
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
# ############# 微信 ##############
WECHAT_CONFIG = {
'app_id': '您的微信app测试id', # 微信给的测试app id
'appsecret': '您的微信app测试secret', # 微信给的测试app sercret
'redirect_uri': 'http://您的域名地址/callback/', # 用户关注之后微信回传地址
'template_id': "您的微信测试模板id" # 模板id
}
settings主要的改动部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
{% csrf_token %}
<input type="text" name="user" placeholder="用户名">
<input type="password" name="pwd" placeholder="密码">
<input type="submit" value="登录">
</form>
</body>
</html>
html:login.html
总结:
感觉还是挺简单的,就是对于刚接触的朋友来说的话,可能不习惯去看第三方的API文档,也不知道怎么下手,多研究就行了,熟练了就很快了
微信支付那个,我没有企业相关材料,而且就算有,也不敢那么随意的就为了做个测试就去申请什么的,所以相关的还是看官方文档吧
前后端分离djangorestframework—— 接入微信模板消息推送的更多相关文章
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
- C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是"模板消息"的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信 ...
- java开发微信模板消息推送
发布时间:2018-12-12 技术:springboot+maven 概述 该demo主要涉及微信模板消息推送功能, 详细 代码下载:http://www.demodashi.com/dem ...
- 前后端分离djangorestframework—— 接入第三方的验证码平台
关于验证码部分,在我这篇文章里说的挺详细的了:Python高级应用(3)—— 为你的项目添加验证码 这里还是再给一个前后端分离的实例,因为极验官网给的是用session作为验证的,而我们做前后端分离的 ...
- qhfl-9 微信模板消息推送
开发中用的是测试号 微信公众号认证流程 用户登陆 <!DOCTYPE html> <html lang="en"> <head> <met ...
- 前后端分离djangorestframework—— 接入支付宝支付平台
支付宝 简介 支付宝是什么不用多说了,本次教程适合初学者 前提准备 话不多说,干就完了 1.注册开发者账号,设置公钥私钥 首先进入支付宝开发者平台:传送门 ,有账号直接登录,没账号用你平时用来付款收钱 ...
- 前后端分离djangorestframework—— 在线视频平台接入第三方加密防盗录视频
加密视频 在以后的开发项目中,很可能有做在线视频的,而在线视频就有个问题,因为在线播放,就很有可能视频数据被抓包,如果这个在线视频平台有付费视频的话,这样就会有人做点倒卖视频的生意了,针对这个问题,目 ...
- 前后端分离djangorestframework——分页组件
Pagination 为什么要分页也不用多说了,大家都懂,DRF也自带了分页组件 这次用 前后端分离djangorestframework——序列化与反序列化数据 文章里用到的数据,数据库用的my ...
- 前后端分离djangorestframework——路由组件
在文章前后端分离djangorestframework——视图组件 中,见识了DRF的视图组件强大,其实里面那个url也是可以自动生成的,就是这么屌 DefaultRouter urls文件作如下调整 ...
随机推荐
- linux入门--Linux系统的优缺点
1) 大量的可用软件及免费软件 Linux 系统上有着大量的可用软件,且绝大多数是免费的,比如声名赫赫的 Apache.Samba.PHP.MySQL 等,构建成本低廉,是 Linux 被众多企业青睐 ...
- 如何解决http请求返回结果中文乱码
如何解决http请求返回结果中文乱码 1.问题描述 http请求中,请求的结果集中包含中文,最终以乱码展示. 2.问题的本质 乱码的本质是服务端返回的字符集编码与客户端的编码方式不一致. 场景的如服务 ...
- python网络-计算机网络基础(23)
一.网络简介 网络是由节点和连线构成,表示诸多对象及其相互联系. 一个人玩: 两个人玩: 多个人玩: 说明 网络就是一种辅助双方或者多方能够连接在一起的工具 如果没有网络可想单机的世界是多么的孤单 使 ...
- innerHTML,outerHTML,innerText,outerText
- innerHTML 设置或获取位于对象起始和结束标签内的 HTML - outerHTML 设置或获取对象及其内容的 HTML 形式 - innerText 设置或获取位于对象起始和结束标签内的文 ...
- Java Runtime.exec()的使用
Sun的doc里其实说明还有其他的用法: exec(String[] cmdarray, String[] envp, File dir) Executes the specified command ...
- Python内置函数(5)——bin
英文文档: bin(x) Convert an integer number to a binary string. The result is a valid Python expression. ...
- Redis分区
数据是怎样分布在多个Redis实例上的 分区是将你的数据分布在多个Redis实例上,以至于每个实例只包含一部分数据. 为什么分区是有用的呢 Redis分区有两个主要目标: 它允许更大的数据库,用许多计 ...
- SpringBoot入门教程(二)CentOS部署SpringBoot项目从0到1
在之前的博文<详解intellij idea搭建SpringBoot>介绍了idea搭建SpringBoot的详细过程, 并在<CentOS安装Tomcat>中介绍了Tomca ...
- 前端笔记之HTML5&CSS3(中)选择器&伪类伪元素&CSS3效果&渐变背景&过渡
一.CSS3选择器 CSS3是CSS的第三代版本,新增了很多功能,例如:强大的选择器.盒模型.圆角.渐变.动画.2D/3D转换.文字特效等. CSS3和HTML5没有任何关系!HTML5骨架中,可以用 ...
- PC逆向之代码还原技术,第一讲基本数据类型在内存中的表现形式.浮点,指针寻址公式
目录 代码还原技术 一丶简介代码还原 二丶代码还原中的数据类型表现形式 1.整数类型 2.无符号整数 3.有符号整数 4.浮点数数据类型 5.浮点编码 4.Double类型解析. 三丶浮点汇编 1.浮 ...