Python实现的微信支付方式总结【三种方式】

时间:2022-09-13 22:48:39

本文实例讲述了python实现的微信支付方式。分享给大家供大家参考,具体如下:

一、准备环境

1、要有微信公众号,商户平台账号

https://pay.weixin.qq.com/wiki/doc/api/index.html

2、支持的支付方式有

Python实现的微信支付方式总结【三种方式】

3、备案域名

选择扫码支付,如果使用模式二则不需要域名,只需要可访问的ip地址就行。

4、建一个django项目。

一、扫码支付

点击“扫码支付”按官方文档配置好回调url(具体如何配置看官网)
先从公众号上获取app_idapp_secrect,从商户平台上获取mch_idapi_key

1、使用模式一生成支付二维码

这个二维码是没有时间限制的。

create_qrcode.html

创建二维码页面

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>生成扫码支付二维码</title>
</head>
<body>
<form method="post" action="/wxpay/qrcode/" >
输入手机号:<input name="phone"/>
<input id="submit" type="submit" value="生成二维码">
  <br>
  {% if img_url %}
    <img src="{{ img_url }}" style="width: 200px;height: 200px"/>
  {% endif %}
<br>
{{ url }}
</form>
</body>
</html>

pay_settings.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#微信支付配置
# ========支付相关配置信息===========
import random
import time
import hashlib
from random import random
import qrcode
from bs4 import beautifulsoup
app_id = "xxx" # 你公众账号上的appid
mch_id = "xxx" # 你的商户号
api_key = "xxx" # 微信商户平台(pay.weixin.qq.com) -->账户设置 -->api安全 -->密钥设置,设置完成后把密钥复制到这里
app_secrect = "xxx"
ufdoder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 该url是微信下单api
notify_url = "http://xxx/" # 微信支付结果回调接口,需要改为你的服务器上处理结果回调的方法路径
create_ip = 'xxx' # 你服务器的ip
def random_str(randomlength=8):
  """
  生成随机字符串
  :param randomlength: 字符串长度
  :return:
  """
  str = ''
  chars = 'aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz0123456789'
  length = len(chars) - 1
  random = random()
  for i in range(randomlength):
    str+=chars[random.randint(0, length)]
  return str
def order_num(phone):
  """
  生成扫码付款订单号
  :param phone: 手机号
  :return:
  """
  local_time = time.strftime('%y%m%d%h%m%s', time.localtime(time.time()))
  result = phone + 't' + local_time + random_str(5)
  return result
def get_sign(data_dict, key):
  # 签名函数,参数为签名的数据和密钥
  params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=false) # 参数字典倒排序为列表
  params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
  # 组织参数字符串并在末尾添加商户交易密钥
  md5 = hashlib.md5() # 使用md5加密模式
  md5.update(params_str.encode('utf-8')) # 将参数字符串传入
  sign = md5.hexdigest().upper() # 完成加密并转为大写
  return sign
def trans_dict_to_xml(data_dict): # 定义字典转xml的函数
  data_xml = []
  for k in sorted(data_dict.keys()): # 遍历字典排序后的key
    v = data_dict.get(k) # 取出字典中key对应的value
    if k == 'detail' and not v.startswith('<![cdata['): # 添加xml标记
      v = '<![cdata[{}]]>'.format(v)
    data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
  return '<xml>{}</xml>'.format(''.join(data_xml)).encode('utf-8') # 返回xml,并转成utf-8,解决中文的问题
def trans_xml_to_dict(data_xml):
  soup = beautifulsoup(data_xml, features='xml')
  xml = soup.find('xml') # 解析xml
  if not xml:
    return {}
  data_dict = dict([(item.name, item.text) for item in xml.find_all()])
  return data_dict
def wx_pay_unifiedorde(detail):
  """
  访问微信支付统一下单接口
  :param detail:
  :return:
  """
  detail['sign'] = get_sign(detail, api_key)
  # print(detail)
  xml = trans_dict_to_xml(detail) # 转换字典为xml
  response = requests.request('post', ufdoder_url, data=xml) # 以post方式向微信公众平台服务器发起请求
  # data_dict = trans_xml_to_dict(response.content) # 将请求返回的数据转为字典
  return response.content
def pay_fail(err_msg):
  """
  微信支付失败
  :param err_msg: 失败原因
  :return:
  """
  data_dict = {'return_msg': err_msg, 'return_code': 'fail'}
  return trans_dict_to_xml(data_dict)
def create_qrcode(phone,url):
  """
  生成扫码支付二维码
  :param phone: 手机号
  :param url: 支付路由
  :return:
  """
  img = qrcode.make(url) # 创建支付二维码片
  # 你存放二维码的地址
  img_url = r'media/qrcode' + '/' + phone + '.png'
  img.save(img_url)
  return img_url

views.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from django.shortcuts import render
from django.http import httpresponse
from django.views import view
from django.views.decorators.csrf import csrf_exempt
from pay_settings.py import *
class wxpay_qrccode(view):
  """
  生成微信支付二维码
  """
  def get(self, request, *args, **kwargs):
    return render(request, 'create_qrcode.html')
  def post(self, request, *args, **kwargs):
    """
    # 生成可扫码支付的二维码
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    phone = request.data.get('phone', none)
    if not phone:
      return httpresponse('手机号获取失败')
    paydict = {
      'appid': app_id,
      'mch_id': mch_id,
      'nonce_str': random_str(phone),
      'product_id': phone, # 商品id,可自定义
      'time_stamp': int(time.time()),
    }
    paydict['sign'] = get_sign(paydict, api_key)
    url = "weixin://wxpay/bizpayurl?appid=%s&mch_id=%s&nonce_str=%s&product_id=%s&time_stamp=%s&sign=%s" \
       % (paydict['appid'], paydict['mch_id'], paydict['nonce_str'], paydict['product_id'], paydict['time_stamp'], paydict['sign'])
    # 可以直接在微信中点击该url,如果有错误,微信会弹出提示框,如果是扫码,如果失败,什么提示都没有,不利于调试
    print(url)
    # 创建二维码
    img_url = create_qrcode(url)
    return render(request, 'create_qrcode.html', context={'img_url': img_url})
@method_decorator(csrf_exempt, name='dispatch')
class wxpay_modelone_pay(view):
  """
  使用微信扫一扫扫描二维码,微信系统会自动回调此路由,post请求
  """
  def post(self, request, *args, **kwargs):
    """
    扫描二维码后,微信系统回调的地址处理
    微信传来的参数格式经trans_xml_to_dict()转成字典
    {'openid': 'xxx',
     'is_subscribe': 'y',
     'mch_id': 'xxx',
     'nonce_str': 'xxx',
     'sign': 'xxx',
     'product_id': 'xxx',
     'appid': 'xxx'}
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    data_dict = trans_xml_to_dict(request.body) # 回调数据转字典
    sign = data_dict.pop('sign') # 取出签名
    key = api_key # 商户交易密钥
    back_sign = get_sign(data_dict, key) # 计算签名
    if sign == back_sign: # 验证签名是否与回调签名相同
      total_fee = 1 # 付款金额,单位是分,必须是整数
      params = {
        'appid': app_id, # appid
        'mch_id': mch_id, # 商户号
        'nonce_str': random_str(16), # 随机字符串
        'out_trade_no': order_num(data_dict['product_id']), # 订单编号
        'total_fee': total_fee, # 订单总金额
        'spbill_create_ip': create_ip, # 发送请求服务器的ip地址
        'notify_url': notify_url,
        'body': 'xxx公司'# 商品描述
        'detail': 'xxx商品', # 商品详情
        'trade_type': 'native', # 扫码支付类型
      }
      # 调用微信统一下单支付接口url
      notify_result = wx_pay_unifiedorde(params)
      #print(trans_xml_to_dict(notify_result))
      return httpresponse(notify_result)
    return httpresponse(pay_fail('交易信息有误,请重新扫码'))

2、使用模式二生成支付二维码

这个二维码是有时间限制的。

模式二与模式一相比,流程更为简单,不依赖设置的回调支付url。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。具体流程看微信公众号。

主体代码:

pay_settings.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#微信支付配置
# ========支付相关配置信息===========
import random
import time
import hashlib
from random import random
from bs4 import beautifulsoup
app_id = "xxx" # 你公众账号上的appid
mch_id = "xxx" # 你的商户号
api_key = "xxx" # 微信商户平台(pay.weixin.qq.com) -->账户设置 -->api安全 -->密钥设置,设置完成后把密钥复制到这里
app_secrect = "xxx"
ufdoder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 该url是微信下单api
notify_url = "http://xxx/" # 微信支付结果回调接口,需要改为你的服务器上处理结果回调的方法路径
create_ip = 'xxx' # 你服务器的ip
def get_sign(data_dict, key):
  """
  签名函数
  :param data_dict: 需要签名的参数,格式为字典
  :param key: 密钥 ,即上面的api_key
  :return: 字符串
  """
  params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=false) # 参数字典倒排序为列表
  params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
  # 组织参数字符串并在末尾添加商户交易密钥
  md5 = hashlib.md5() # 使用md5加密模式
  md5.update(params_str.encode('utf-8')) # 将参数字符串传入
  sign = md5.hexdigest().upper() # 完成加密并转为大写
  return sign
def order_num(phone):
  """
  生成扫码付款订单号
  :param phone: 手机号
  :return:
  """
  local_time = time.strftime('%y%m%d%h%m%s', time.localtime(time.time()))
  result = phone + 't' + local_time + random_str(5)
  return result
def random_str(randomlength=8):
  """
  生成随机字符串
  :param randomlength: 字符串长度
  :return:
  """
  strs = ''
  chars = 'aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz0123456789'
  length = len(chars) - 1
  random = random()
  for i in range(randomlength):
    strs += chars[random.randint(0, length)]
  return strs
def trans_dict_to_xml(data_dict):
  """
  定义字典转xml的函数
  :param data_dict:
  :return:
  """
  data_xml = []
  for k in sorted(data_dict.keys()): # 遍历字典排序后的key
    v = data_dict.get(k) # 取出字典中key对应的value
    if k == 'detail' and not v.startswith('<![cdata['): # 添加xml标记
      v = '<![cdata[{}]]>'.format(v)
    data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
  return '<xml>{}</xml>'.format(''.join(data_xml)) # 返回xml
def trans_xml_to_dict(data_xml):
  """
  定义xml转字典的函数
  :param data_xml:
  :return:
  """
  soup = beautifulsoup(data_xml, features='xml')
  xml = soup.find('xml') # 解析xml
  if not xml:
    return {}
  data_dict = dict([(item.name, item.text) for item in xml.find_all()])
  return data_dict

views.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import qrcode
from django.shortcuts import render
from pay_settings import *
from django.http import httpresponse
from django.views import view
class wxpayview(view):
  def get(self,request):
    # 在info.html有一个按钮,点击后跳转到这个类的post()中,具体urls.py设置不详述
    return render(request, 'info.html')
  def post(self,request):
    phone = request.post.get('phone','')
    if not phone:
      return render(request, 'info.html', {'err_msg': '获取手机号失败'})
    data_dict = wxpay(phone)
    if data_dict.get('return_code') == 'success': # 如果请求成功
      qrcode_name = phone + '.png' # 二维码图片名称
      img = qrcode.make(data_dict.get('code_url')) # 创建支付二维码片
      img.save(r'static' + '/' + qrcode_name)
      return render(request, 'qrcode.html', {'qrcode_img': qrcode_name})
    return render(request, 'info.html', {'err_msg': '获取微信的code_url失败'})
def wxpay(phone):
  nonce_str = random_str() # 拼接出随机的字符串即可,我这里是用 时间+随机数字+5个随机字母
  total_fee = 1 # 付款金额,单位是分,必须是整数
  params = {
    'appid': app_id, # appid
    'mch_id': mch_id, # 商户号
    'nonce_str': nonce_str,  # 随机字符串
    'out_trade_no': order_num(phone), # 订单编号,可自定义
    'total_fee': total_fee, # 订单总金额
    'spbill_create_ip': create_ip, # 自己服务器的ip地址
    'notify_url': notify_url, # 回调地址,微信支付成功后会回调这个url,告知商户支付结果
    'body': 'xxx公司', # 商品描述
    'detail': 'xxx商品', # 商品描述
    'trade_type': 'native', # 扫码支付类型
  }
  sign = get_sign(params,api_key) # 获取签名
  params['sign'] = sign # 添加签名到参数字典
  # print(params)
  xml = trans_dict_to_xml(params) # 转换字典为xml
  response = requests.request('post', settings._ufdoder_url, data=xml) # 以post方式向微信公众平台服务器发起请求
  data_dict = trans_xml_to_dict(response.content) # 将请求返回的数据转为字典
  return data_dict
class wxpay_result(view):
  """
  微信支付结果回调通知路由
  """
  def get(self, request, *args, **kwargs):
    machine_code = request.get.get('machine_code', '获取机器编号失败')
    # 返回支付成功页面,可自定义
    return render(request, 'zfcg.html', {'machine': {'machine_code': machine_code}})
  def post(self, request, *args, **kwargs):
    """
    微信支付成功后会自动回调
    返回参数为:
    {'mch_id': '',
    'time_end': '',
    'nonce_str': '',
    'out_trade_no': '',
    'trade_type': '',
    'openid': '',
     'return_code': '',
     'sign': '',
     'bank_type': '',
     'appid': '',
     'transaction_id': '',
     'cash_fee': '',
     'total_fee': '',
     'fee_type': '', '
     is_subscribe': '',
     'result_code': 'success'}
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    data_dict = trans_xml_to_dict(request.body) # 回调数据转字典
    # print('支付回调结果', data_dict)
    sign = data_dict.pop('sign') # 取出签名
    back_sign = get_sign(data_dict, api_key) # 计算签名
    # 验证签名是否与回调签名相同
    if sign == back_sign and data_dict['return_code'] == 'success':
      '''
      检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。
      '''
      print('微信支付成功会回调!')
      # 处理支付成功逻辑
      # 返回接收结果给微信,否则微信会每隔8分钟发送post请求
      return httpresponse(trans_dict_to_xml({'return_code': 'success', 'return_msg': 'ok'}))
    return httpresponse(trans_dict_to_xml({'return_code': 'fail', 'return_msg': 'signerror'}))

二、使用jsapi发起微信支付

在微信公众号中左下角 设置->公众号设置->功能设置,把业务域名,js接口安全域名,网页授权域名设置好。

用户在微信中点击一个路由url(可把这个url封装成二维码).在后台中的views.py中的wxjsapipay类中使用get()函数处理用户的请求,先获取用户的openid,然后调用微信统一下单接口,获取prepay_id,具体看官网。

wx_js_pay.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" id="vp"/>
{#    <script type="text/javascript" src="/static/js/rem.js"></script>#}
{#    <link rel="stylesheet" type="text/css" href="/static/css/base.css" rel="external nofollow" />#}
{#    <link rel="stylesheet" type="text/css" href="/static/css/index.css" rel="external nofollow" />#}
  </head>
  <body>
    <div class="bigbox">
      <div class="top">
        <span>订单详情</span>
      </div>
      <div class="zhong">
      </div>
      <div class="zhifu">
        <button class="btn" type="button" onclick="javascript:callpay();return false;">立即支付</button>
      </div>
    </div>
<script src="https://cdn.bootcss.com/jquery/1.12.1/jquery.js"></script>
<script type="text/javascript">
  //调用微信js api 支付
  function onbridgeready() {
    weixinjsbridge.invoke(
      'getbrandwcpayrequest',
      {
        appid: "{{ params.appid }}",    //公众号名称,由商户传入
        timestamp: "{{ params.timestamp }}", //时间戳,自1970年以来的秒数
        noncestr: "{{ params.noncestr }}", //随机串
        package: "prepay_id={{ params.prepay_id }}", //预支付id
        signtype: "md5", //微信签名方式
        paysign: "{{ params.sign }}"   //微信签名
      },
      function (res) {
        //支付成功后返回 get_brand_wcpay_request:ok
        if (res.err_msg == "get_brand_wcpay_request:ok") {
          // 跳转到支付成功的页面
          window.location.href = '#';
          {#alert('支付成功');#}
        } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
          alert("您已取消支付!");
          {#alert({{ params.machine_code }});#}
          {#window.location.href = '';#}
        } else if (res.err_msg == "get_brand_wcpay_request:fail") {
          $.each(res, function(key,value){
            alert(value);
            });
          alert("支付失败!");
        }
      }
    );
  }
  function callpay() {
    if (typeof weixinjsbridge == "undefined") {
      if (document.addeventlistener) {
        document.addeventlistener('weixinjsbridgeready', onbridgeready, false);
      } else if (document.attachevent) {
        document.attachevent('weixinjsbridgeready', onbridgeready);
        document.attachevent('onweixinjsbridgeready', onbridgeready);
      }
    } else {
      onbridgeready();
    }
  }
</script>
  </body>
</html>

pay_settings.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# encoding: utf-8
import hashlib
import time
import requests
from collections import ordereddict
from random import random
from bs4 import beautifulsoup
app_id = "xxx" # 公众账号appid
mch_id = "xxx" # 商户号
api_key = "xxx" # 微信商户平台(pay.weixin.qq.com) -->账户设置 -->api安全 -->密钥设置,设置完成后把密钥复制到这里
app_secrect = "xxx"
ufdoder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder" # url是微信下单api
notify_url = "http://xxx/wxpay/pay_result/" # 微信支付结果回调接口,需要你自定义
create_ip = 'xxx' # 你服务器上的ip
# 生成随机字符串
def random_str(randomlength=8):
  """
  生成随机字符串
  :param randomlength: 字符串长度
  :return:
  """
  str = ''
  chars = 'aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz0123456789'
  length = len(chars) - 1
  random = random()
  for i in range(randomlength):
    str+=chars[random.randint(0, length)]
  return str
def order_num(phone):
  """
  生成扫码付款订单,
  :param phone:
  :return:
  """
  local_time = time.strftime('%y%m%d%h%m%s', time.localtime(time.time()))
  result = phone + 't' + local_time + random_str(5)
  return result
def get_sign(data_dict, key):
  # 签名函数,参数为签名的数据和密钥
  params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=false) # 参数字典倒排序为列表
  params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
  # 组织参数字符串并在末尾添加商户交易密钥
  md5 = hashlib.md5() # 使用md5加密模式
  md5.update(params_str.encode('utf-8')) # 将参数字符串传入
  sign = md5.hexdigest().upper() # 完成加密并转为大写
  return sign
def trans_dict_to_xml(data_dict): # 定义字典转xml的函数
  data_xml = []
  for k in sorted(data_dict.keys()): # 遍历字典排序后的key
    v = data_dict.get(k) # 取出字典中key对应的value
    if k == 'detail' and not v.startswith('<![cdata['): # 添加xml标记
      v = '<![cdata[{}]]>'.format(v)
    data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
  return '<xml>{}</xml>'.format(''.join(data_xml)).encode('utf-8') # 返回xml,并转成utf-8,解决中文的问题
def trans_xml_to_dict(data_xml):
  soup = beautifulsoup(data_xml, features='xml')
  xml = soup.find('xml') # 解析xml
  if not xml:
    return {}
  data_dict = dict([(item.name, item.text) for item in xml.find_all()])
  return data_dict
def wx_pay_unifiedorde(detail):
  """
  访问微信支付统一下单接口
  :param detail:
  :return:
  """
  detail['sign'] = get_sign(detail, api_key)
  # print(detail)
  xml = trans_dict_to_xml(detail) # 转换字典为xml
  response = requests.request('post', ufdoder_url, data=xml) # 以post方式向微信公众平台服务器发起请求
  # data_dict = trans_xml_to_dict(response.content) # 将请求返回的数据转为字典
  return response.content
def get_redirect_url():
  """
  获取微信返回的重定向的url
  :return: url,其中携带code
  """
  wechatcode = 'https://open.weixin.qq.com/connect/oauth2/authorize'
  urlinfo = ordereddict()
  urlinfo['appid'] = app_id
  urlinfo['redirect_uri'] = 'http://xxx/wxjsapipay/?getinfo=yes' # 设置重定向路由
  urlinfo['response_type'] = 'code'
  urlinfo['scope'] = 'snsapi_base' # 只获取基本信息
  urlinfo['state'] = 'mywxpay'  # 自定义的状态码
  info = requests.get(url=wechatcode, params=urlinfo)
  return info.url
def get_openid(code,state):
  """
  获取微信的openid
  :param code:
  :param state:
  :return:
  """
  if code and state and state == 'mywxpay':
    wechatcode = 'https://api.weixin.qq.com/sns/oauth2/access_token'
    urlinfo = ordereddict()
    urlinfo['appid'] = app_id
    urlinfo['secret'] = app_secrect
    urlinfo['code'] = code
    urlinfo['grant_type'] = 'authorization_code'
    info = requests.get(url=wechatcode, params=urlinfo)
    info_dict = eval(info.content.decode('utf-8'))
    return info_dict['openid']
  return none
def get_jsapi_params(openid):
  """
  获取微信的jsapi支付需要的参数
  :param openid: 用户的openid
  :return:
  """
  total_fee = 1 # 付款金额,单位是分,必须是整数
  params = {
    'appid': app_id, # appid
    'mch_id': mch_id, # 商户号
    'nonce_str': random_str(16), # 随机字符串
    'out_trade_no': order_num('123'), # 订单编号,可自定义
    'total_fee': total_fee, # 订单总金额
    'spbill_create_ip': create_ip, # 发送请求服务器的ip地址
    'openid': openid,
    'notify_url': notify_url, # 支付成功后微信回调路由
    'body': 'xxx公司', # 商品描述
    'trade_type': 'jsapi', # 公众号支付类型
  }
  # print(params)
  # 调用微信统一下单支付接口url
  notify_result = wx_pay_unifiedorde(params)
  params['prepay_id'] = trans_xml_to_dict(notify_result)['prepay_id']
  params['timestamp'] = int(time.time())
  params['noncestr'] = random_str(16)
  params['sign'] = get_sign({'appid': app_id,
                "timestamp": params['timestamp'],
                'noncestr': params['noncestr'],
                'package': 'prepay_id=' + params['prepay_id'],
                'signtype': 'md5',
                },
               api_key)
  return params

views.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from django.http import httpresponseredirect, httpresponse
from django.shortcuts import render
from django.views import view
from pay_settings import *
class wxjsapipay(view):
  def get(self, request, *args, **kwargs):
    """
    用户点击一个路由或者扫码进入这个views.py中的函数,首先获取用户的openid,
    使用jsapi方式支付需要此参数
    :param self:
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    getinfo = request.get.get('getinfo', none)
    openid = request.cookies.get('openid', '')
    if not openid:
      if getinfo != 'yes':
      # 构造一个url,携带一个重定向的路由参数,
      # 然后访问微信的一个url,微信会回调你设置的重定向路由,并携带code参数
        return httpresponseredirect(get_redirect_url())
      elif getinfo == 'yes':
   # 我设置的重定向路由还是回到这个函数中,其中设置了一个getinfo=yes的参数
      # 获取用户的openid
        openid = get_openid(request.get.get('code'), request.get.get('state', ''))
        if not openid:
          return httpresponse('获取用户openid失败')
        response = render_to_response('wx_js_pay.html', context={'params': get_jsapi_params(openid)})
        response.set_cookie('openid', openid, expires=60 * 60 * 24 *30)
        return response
      else:
        return httpresponse('获取机器编码失败')
    else:
      return render(request, 'wx_js_pay.html', context={'params': get_jsapi_params(openid)})

希望本文所述对大家python程序设计有所帮助。

原文链接:https://blog.csdn.net/lm_is_dc/article/details/83312706