当前位置:首页 > 技术 > 正文内容

使用 Django 实现微信模板消息推送

访客 技术 2026年10月27日 2

本文将介绍如何使用 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 函数应实现缓存机制以提高效率和避免超限。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。