使用 Django 实现微信模板消息推送
本文将介绍如何使用 Python 的 Django 框架来实现微信公众号的消息推送功能,特别是针对模板消息的发送。
前提条件
- Python 3 环境
- Django 1.11.9 框架
- 拥有一个可访问的服务器用于微信 Token 验证。
测试账号设置
在实际开发前,建议使用微信公众平台提供的测试账号进行开发和调试。您可以访问 微信公众平台测试接口 页面,通过扫描二维码获取一个测试账号。登录后,您需要点击"新增测试模板"按钮,并按照提示填写相关信息来创建您的测试模板。请注意模板 ID 的获取和使用。
项目配置
URL 路由配置 (urls.py)
在 Django 项目的 urls.py 文件中,需要添加相应的路由来处理微信相关的请求:
urlpatterns = [
# ... 其他路由
path('wechat/bind/', views.wechat_bind, name='wechat_bind'),
path('wechat/qrcode/', views.wechat_qrcode, name='wechat_qrcode'),
path('wechat/callback/', views.wechat_callback, name='wechat_callback'),
path('wechat/send/', views.wechat_send_message, name='wechat_send_message'),
]
设置文件配置 (settings.py)
在 Django 的 settings.py 文件中,定义微信相关的配置信息:
WECHAT_CONFIG = {
'app_id': 'YOUR_TEST_APP_ID',
'app_secret': 'YOUR_TEST_APP_SECRET',
'redirect_uri': 'YOUR_SERVER_CALLBACK_URL', # 例如: 'http://yourdomain.com/wechat/callback/'
'template_id': 'YOUR_TEMPLATE_ID',
}
视图函数实现 (views.py)
以下是处理微信相关逻辑的视图函数示例:
import json
import requests
from django.conf import settings
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse
# 假设您有一个 UserInfo 模型用于存储用户数据,包括微信 openid
# from .models import UserInfo
def wechat_bind(request):
"""
用户关注公众号的入口,引导用户进行扫码绑定。
"""
# 渲染一个包含生成二维码按钮的页面
return render(request, 'wechat/bind.html')
def wechat_qrcode(request):
"""
生成引导用户授权的二维码链接。
"""
# 假设 request.session['user_info']['uid'] 存储了当前用户的唯一标识
user_uid = request.session.get('user_info', {}).get('uid', 'default_state')
auth_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"
)
full_auth_url = auth_url.format(
appid=settings.WECHAT_CONFIG["app_id"],
redirect_uri=settings.WECHAT_CONFIG["redirect_uri"],
state=user_uid
)
return JsonResponse({'url': full_auth_url})
def wechat_callback(request):
"""
微信服务器回调接口,用于获取用户的 openid。
当用户扫描二维码并授权后,微信会重定向到此接口。
"""
code = request.GET.get("code")
state = request.GET.get("state") # 用于标识是哪个用户的授权请求
if not code:
return HttpResponse("授权失败,未获取到 code。", status=400)
# 通过 code 获取 access_token 和 openid
token_url = "https://api.weixin.qq.com/sns/oauth2/access_token"
token_params = {
"appid": settings.WECHAT_CONFIG["app_id"],
"secret": settings.WECHAT_CONFIG["app_secret"],
"code": code,
"grant_type": 'authorization_code',
}
response = requests.get(token_url, params=token_params)
token_data = response.json()
openid = token_data.get("openid")
if openid:
# 将获取到的 openid 与用户关联并保存
# UserInfo.objects.filter(uid=state).update(wx_openid=openid)
return HttpResponse(f"<h1>微信授权成功!您的 OpenID 是: {openid}</h1>")
else:
error_msg = token_data.get("errmsg", "未知错误")
return HttpResponse(f"<h1>微信授权失败: {error_msg}</h1>", status=500)
def get_global_access_token():
"""
获取微信全局接口的 access_token。
建议实现缓存机制以避免频繁请求。
"""
token_url = "https://api.weixin.qq.com/cgi-bin/token"
params = {
"grant_type": "client_credential",
"appid": settings.WECHAT_CONFIG['app_id'],
"secret": settings.WECHAT_CONFIG['app_secret'],
}
response = requests.get(token_url, params=params)
data = response.json()
return data.get('access_token')
def send_template_message(request):
"""
发送模板消息给指定用户。
"""
access_token = get_global_access_token()
if not access_token:
return HttpResponse("获取 Access Token 失败。", status=500)
# 假设从数据库获取目标用户的 openid
# target_user = UserInfo.objects.filter(id=1).first()
# openid = target_user.wx_openid if target_user else None
# for demonstration purposes, use a hardcoded openid
openid = "TARGET_USER_OPENID" # 替换为实际要发送消息的用户的 openid
if not openid:
return HttpResponse("未找到目标用户的 OpenID。", status=400)
template_id = settings.WECHAT_CONFIG['template_id']
# 构造模板消息内容
message_data = {
"touser": openid,
"template_id": template_id,
"data": {
"first": {
"value": "您好!",
"color": "#173177"
},
"keyword1": {
"value": "订单通知", # 示例:通知类型
"color": "#173177"
},
"keyword2": {
"value": "您的订单已发货", # 示例:通知内容
"color": "#173177"
},
"remark": {
"value": "请注意查收。",
"color": "#173177"
}
}
}
send_url = f"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={access_token}"
response = requests.post(send_url, json=message_data)
result = response.json()
if result.get('errcode') == 0:
return HttpResponse('模板消息发送成功')
else:
error_message = result.get('errmsg', '未知错误')
return HttpResponse(f'模板消息发送失败: {error_message}', status=500)
# 示例:如果需要发送客服消息,可以参考以下方法 (非模板消息)
def send_custom_message(request):
access_token = get_global_access_token()
if not access_token:
return HttpResponse("获取 Access Token 失败。", status=500)
openid = "TARGET_USER_OPENID" # 替换为实际要发送消息的用户的 openid
message_body = {
"touser": openid,
"msgtype": "text",
"text": {
"content": '这是一条测试文本消息!'
}
}
send_url = f"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={access_token}"
response = requests.post(send_url, data=json.dumps(message_body, ensure_ascii=False).encode('utf-8'))
result = response.json()
if result.get('errcode') == 0:
return HttpResponse('客服消息发送成功')
else:
error_message = result.get('errmsg', '未知错误')
return HttpResponse(f'客服消息发送失败: {error_message}', status=500)
注意:上述代码为示例,部分逻辑(如用户信息的获取和存储)需要根据您的具体项目需求进行调整和完善。例如,get_global_access_token 函数应实现缓存机制以提高效率和避免超限。