Django1.11配合uni-app发起微信支付的实现


Posted in Python onOctober 12, 2019

Django1.11配合uni-app发起微信支付!

经过三天的断断续续的奋战,我终于是干动了微信支付。为了以后不忘记,现在来一篇教程,来来来,开干!!!

Django1.11配合uni-app发起微信支付的实现

一、准备阶段

1、准备阶段我们需要去微信官网申请一个小程序或者公众号。获得AppID和AppSecret。

Django1.11配合uni-app发起微信支付的实现

2、去微信商户平台 成为商家,开通JSAPI用来获得商户号和自己配置的钥匙。然后再商户平台上面绑定小程序appid。

Django1.11配合uni-app发起微信支付的实现

(点击下面图片进入官方链接!)

Django1.11配合uni-app发起微信支付的实现

在配置里面配置一个自己的key,需要记住后台开发的时候需要!

Django1.11配合uni-app发起微信支付的实现

关联后即可在小程序管理页面开通微信支付!

Django1.11配合uni-app发起微信支付的实现

到此,准备阶段完成!

二、梳理流程

在这里我大概写一下流程:首先我们在前端发起微信登陆,此时微信会给我们返回一个openid,这个openid一定要留存在某一个位置。然后前段发起微信支付,向后端发送数据请求,后端对结合前段的数据向微信方面发送一个请求,请求相关数据,得到相关数据之后把数据发送给前段,前段收到数据,利用微信接口再向微信指定连接发送请求,微信返回请求,即可!这个就是全流程,很多人肯定已经懵了。没事,咱一步一步来,别步子跨大了——扯到蛋了!

Django1.11配合uni-app发起微信支付的实现

以上就是数据处理阶段大概流程!

三、代码实现

0、用户登录根据用户code获取openid

uni.login({
          provider: 'weixin',
          success: function(loginRes) {
            let code = loginRes.code;
            if (!_this.isCanUse) {
              //非第一次授权获取用户信息
              uni.getUserInfo({
                provider: 'weixin',
                success: function(infoRes) { 
  









//获取用户信息后向调用信息更新方法
                  _this.nickName = infoRes.userInfo.nickName; //昵称
                  _this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
                    _this.updateUserInfo();//调用更新信息方法
                }
              });
            }
      
            //2.将用户登录code传递到后台置换用户SessionKey、OpenId等信息
            uni.request({
              url: 'http://127.0.0.1:8000/users/',
              data: {
                code: code,
              },
              method: 'GET',
              header: {
                'content-type': 'application/json' 
              },
              success: (res) => {
                console.log(res.data)
                if ( res.data.state== 1001) {
                  console.log("新注册的用户!")
                  _this.OpenId = res.data.openid;
                } else{
                  _this.OpenId = res.data.openid;
                  console.log("注册过的用户!开始设置本地缓存!")
                  console.log(res.data[0].id)
                  if ( res.data[0].id ) {
                    //这里获得登陆状态,然后根据登陆状态来改变用户按钮信息!!!!
                  } else{
                    
                  };
                  _this.user_id = res.data[0].id
                  uni.setStorage({
                    key: 'user',
                    data: res.data,
                    success: function () {
                      console.log('设置缓存成功');
                    }
                  });
                  // _this.gotoshopping()
                  // uni.reLaunch({//信息更新成功后跳转到小程序首页
                  //   url: '/pages/shopping/shopping'
                  // });
                }
                //openId、或SessionKdy存储//隐藏loading
                uni.hideLoading();
              }
            });
          },
        });
if request.GET.get("code"):
      ret = {"state": 1000}
      code = request.GET.get("code")

      url = "https://api.weixin.qq.com/sns/jscode2session"
      appid = "xxxxxxxxxxxxx"
      secret = "xxxxxxxxxxxxxxxxxxxxx"

      # url一定要拼接,不可用传参方式
      url = url + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"
      import requests
      r = requests.get(url)
      print("======", r.json())
      openid = r.json()['openid']
      user = users.objects.filter(openid=openid).all()
      if not user:
        ret["state"] = 1001
        ret["msg"] = "用户第一次登陆"
        ret["openid"] = openid
        return Response(ret)
      else:
        serializer = self.get_serializer(user, many=True)
        return Response(serializer.data)

1、首先需要创建一个confige.py的配置文件!然后写路由,让前端找到“门”在哪里!

config.py

# 微信支付的配置参数
client_appid = 'xxxxxxxxxxxxxx' # 小程序appid
client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx' # 小程序secret

Mch_id = 'xxxxxxxxxxx' # 商户号
Mch_key = 'xxxxxxxxxxxxxxxxxxx' # 商户Key
order_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 订单地址

url.py

router = routers.DefaultRouter()
router.register("users", views.UsersViewSet)
router.register("goods", views.GoodsViewSet)
router.register("comments", views.CommentsViewSet)
router.register("payOrder", views.OrdersViewSet) #这个就是微信支付的接口


urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include(router.urls)),

]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

view.py

class OrdersViewSet(viewsets.ModelViewSet):
  queryset = Order.objects.all()
  serializer_class = OrderModelSerializer

  def create(self, request, *args, **kwargs):
    if request.data.get("user_id"):
      from goods.wxpay.wxpay import payOrder
      data = payOrder(request)
      print(data)
      return Response(data)
    else:
      serializer = self.get_serializer(data=request.data)
      serializer.is_valid(raise_exception=True)
      self.perform_create(serializer)
      headers = self.get_success_headers(serializer.data)
      return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

  def perform_create(self, serializer):
    serializer.save()

  def get_success_headers(self, data):
    try:
      return {'Location': str(data[api_settings.URL_FIELD_NAME])}
    except (TypeError, KeyError):
      return {}

2、然后创建逻辑文件,获取数据请求数据返回数据!

wxpay.py

# -*- coding: utf-8 -*-
from .config import client_appid, client_secret, Mch_id, Mch_key, order_url
import hashlib
import datetime
import xml.etree.ElementTree as ET
import requests
from ..models import users


# 生成签名的函数
def paysign(appid, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee):
  ret = {
    "appid": appid,
    "body": body,
    "mch_id": mch_id,
    "nonce_str": nonce_str,
    "notify_url": notify_url,
    "openid": openid,
    "out_trade_no": out_trade_no,
    "spbill_create_ip": spbill_create_ip,
    "total_fee": total_fee,
    "trade_type": 'JSAPI'
  }
  print(ret)
  # 处理函数,对参数按照key=value的格式,并按照参数名ASCII字典序排序
  stringA = '&'.join(["{0}={1}".format(k, ret.get(k)) for k in sorted(ret)])
  stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key)
  sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
  print(sign.upper())
  return sign.upper()


# 生成随机字符串
def getNonceStr():
  import random
  data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
  nonce_str = ''.join(random.sample(data, 30))
  return nonce_str


# 生成商品订单号
def getWxPayOrdrID():
  date = datetime.datetime.now()
  # 根据当前系统时间来生成商品订单号。时间精确到微秒
  payOrdrID = date.strftime("%Y%m%d%H%M%S%f")

  return payOrdrID


# 获取全部参数信息,封装成xml
def get_bodyData(openid, client_ip, price):
  body = 'Mytest' # 商品描述
  notify_url = 'https://127.0.0.1:8000/payOrder/' # 支付成功的回调地址 可访问 不带参数
  nonce_str = getNonceStr() # 随机字符串
  out_trade_no = getWxPayOrdrID() # 商户订单号
  total_fee = str(price) # 订单价格 单位是 分

  # 获取签名
  sign = paysign(client_appid, body, Mch_id, nonce_str, notify_url, openid, out_trade_no, client_ip, total_fee)

  bodyData = '<xml>'
  bodyData += '<appid>' + client_appid + '</appid>' # 小程序ID
  bodyData += '<body>' + body + '</body>' # 商品描述
  bodyData += '<mch_id>' + Mch_id + '</mch_id>' # 商户号
  bodyData += '<nonce_str>' + nonce_str + '</nonce_str>' # 随机字符串
  bodyData += '<notify_url>' + notify_url + '</notify_url>' # 支付成功的回调地址
  bodyData += '<openid>' + openid + '</openid>' # 用户标识
  bodyData += '<out_trade_no>' + out_trade_no + '</out_trade_no>' # 商户订单号
  bodyData += '<spbill_create_ip>' + client_ip + '</spbill_create_ip>' # 客户端终端IP
  bodyData += '<total_fee>' + total_fee + '</total_fee>' # 总金额 单位为分
  bodyData += '<trade_type>JSAPI</trade_type>' # 交易类型 小程序取值如下:JSAPI
  bodyData += '<sign>' + sign + '</sign>'
  bodyData += '</xml>'

  return bodyData


def xml_to_dict(xml_data):
  '''
  xml to dict
  :param xml_data:
  :return:
  '''
  xml_dict = {}
  root = ET.fromstring(xml_data)
  for child in root:
    xml_dict[child.tag] = child.text
  return xml_dict


def dict_to_xml(dict_data):
  '''
  dict to xml
  :param dict_data:
  :return:
  '''
  xml = ["<xml>"]
  for k, v in dict_data.iteritems():
    xml.append("<{0}>{1}</{0}>".format(k, v))
  xml.append("</xml>")
  return "".join(xml)


# 获取返回给小程序的paySign
def get_paysign(prepay_id, timeStamp, nonceStr):
  pay_data = {
    'appId': client_appid,
    'nonceStr': nonceStr,
    'package': "prepay_id=" + prepay_id,
    'signType': 'MD5',
    'timeStamp': timeStamp
  }
  stringA = '&'.join(["{0}={1}".format(k, pay_data.get(k)) for k in sorted(pay_data)])
  stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key)
  sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
  return sign.upper()


# 统一下单支付接口
def payOrder(request):
  import time
  # 获取价格,和用户是谁
  price = request.data.get("price")
  user_id = request.data.get("user_id")

  # 获取客户端ip
  client_ip, port = request.get_host().split(":")

  # 获取小程序openid
  openid = users.objects.get(id=user_id).openid

  # 请求微信的url
  url = order_url

  # 拿到封装好的xml数据
  body_data = get_bodyData(openid, client_ip, price)

  # 获取时间戳
  timeStamp = str(int(time.time()))

  # 请求微信接口下单
  respone = requests.post(url, body_data.encode("utf-8"), headers={'Content-Type': 'application/xml'})

  # 回复数据为xml,将其转为字典
  content = xml_to_dict(respone.content)
  print(content)
  # 返回给调用函数的数据
  ret = {"state": 1000}
  if content["return_code"] == 'SUCCESS':
    # 获取预支付交易会话标识
    prepay_id = content.get("prepay_id")
    # 获取随机字符串
    nonceStr = content.get("nonce_str")

    # 获取paySign签名,这个需要我们根据拿到的prepay_id和nonceStr进行计算签名
    paySign = get_paysign(prepay_id, timeStamp, nonceStr)

    # 封装返回给前端的数据
    data = {"prepay_id": prepay_id, "nonceStr": nonceStr, "paySign": paySign, "timeStamp": timeStamp}
    print('=========',data)

    ret["msg"] = "成功"
    return data

  else:
    ret["state"] = 1001
    ret["msg"] = "失败"
    return ret

3、前段获取后端返回的数据给微信再次发送数据请求!(包含点击的时候往后端发送数据处理请求)

pay(){
        uni.request({
          url: 'http://127.0.0.1:8000/payOrder/',
          method: 'POST',
          header: {
            'content-type': 'application/json'
          },
          data: {
            user_id:this.user_id,
            price:128
          },
          success: res => {
            console.log("success")
            console.log(res.data)
            
            uni.requestPayment({
            provider: 'wxpay',
            
            timeStamp: res.data.timeStamp,
            nonceStr: res.data.nonceStr,
            package: 'prepay_id='+String(res.data.prepay_id),
            signType: 'MD5',
            paySign: res.data.paySign,
            
            success: function (res) {
              console.log('success:' + JSON.stringify(res));
              // 支付成功,给后台发送数据,保存订单
              
            },
            fail: function (err) {
              console.log('fail:' + JSON.stringify(err));
              // 支付失败,给后台发送数据,保存订单
            }
            });

            
            
          },
          fail: (res) => {
            console.log("fail")
            console.log(res)
          },
          complete: () => {}
        });
        
        
      }

至此相信大家也就会了。

附上我的目录结构

Django1.11配合uni-app发起微信支付的实现

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python简单操作sqlite3的方法示例
Mar 22 Python
Python 多线程实例详解
Mar 25 Python
Python中turtle作图示例
Nov 15 Python
python实现电脑自动关机
Jun 20 Python
TensorFlow实现iris数据集线性回归
Sep 07 Python
python selenium登录豆瓣网过程解析
Aug 10 Python
Pytorch反向求导更新网络参数的方法
Aug 17 Python
在pytorch 中计算精度、回归率、F1 score等指标的实例
Jan 18 Python
超全Python图像处理讲解(多模块实现)
Apr 13 Python
python爬虫利用selenium实现自动翻页爬取某鱼数据的思路详解
Dec 22 Python
Python实现文本文件拆分写入到多个文本文件的方法
Apr 18 Python
Python实现天气查询软件
Jun 07 Python
Python数据处理篇之Sympy系列(五)---解方程
Oct 12 #Python
详解Python绘图Turtle库
Oct 12 #Python
Python中的list与tuple集合区别解析
Oct 12 #Python
Python 生成器,迭代,yield关键字,send()传参给yield语句操作示例
Oct 12 #Python
Python 类,property属性(简化属性的操作),@property,property()用法示例
Oct 12 #Python
python获取全国城市pm2.5、臭氧等空气质量过程解析
Oct 12 #Python
Python 迭代,for...in遍历,迭代原理与应用示例
Oct 12 #Python
You might like
Cakephp 执行主要流程
2010/03/24 PHP
php中用date函数获取当前时间有误的解决办法
2013/08/02 PHP
js实现页面跳转重定向的几种方式
2014/05/29 Javascript
如何使用jQuery技术开发ios风格的页面导航菜单
2015/07/29 Javascript
比例尺、缩略图、平移缩放之百度地图添加控件方法
2015/08/03 Javascript
JS实现的打字机效果完整实例
2016/06/20 Javascript
JavaScript比较当前时间是否在指定时间段内的方法
2016/08/02 Javascript
js 自带的 map() 方法全面了解
2016/08/16 Javascript
简单三步实现报表页面集成天气
2016/12/15 Javascript
jQuery实现标签页效果实战(4)
2017/02/08 Javascript
axios学习教程全攻略
2017/03/26 Javascript
微信小程序实现给循环列表添加点击样式实例
2017/04/26 Javascript
微信小程序三级联动地址选择器的实例代码
2017/07/12 Javascript
原生JS实现Ajax跨域请求flask响应内容
2017/10/24 Javascript
JavaScript函数Call、Apply原理实例解析
2020/02/17 Javascript
JS实现iframe中子父页面跨域通讯的方法分析
2020/03/10 Javascript
如何管理Vue中的缓存页面
2021/02/06 Vue.js
[00:30]塑造者的传承礼包-戴泽“暗影之焰”套装展示视频
2014/04/04 DOTA
用Python和MD5实现网站挂马检测程序
2014/03/13 Python
python进阶教程之循环相关函数range、enumerate、zip
2014/08/30 Python
利用Python的装饰器解决Bottle框架中用户验证问题
2015/04/24 Python
Python函数的参数常见分类与用法实例详解
2019/03/30 Python
详解用Python为直方图绘制拟合曲线的两种方法
2019/08/21 Python
Python 读取 YUV(NV12) 视频文件实例
2019/12/09 Python
Python如何基于selenium实现自动登录博客园
2019/12/16 Python
Python编程快速上手——strip()函数的正则表达式实现方法分析
2020/02/29 Python
Python基于requests库爬取网站信息
2020/03/02 Python
解决python 执行sql语句时所传参数含有单引号的问题
2020/06/06 Python
python 如何利用argparse解析命令行参数
2020/09/11 Python
详解python polyscope库的安装和例程
2020/11/13 Python
pyqt5实现井字棋的示例代码
2020/12/07 Python
美国最大的船只买卖在线市场:Boat Trader
2018/08/04 全球购物
计算机网络专业自荐书
2014/06/09 职场文书
2014年党员自我剖析材料
2014/10/07 职场文书
Python中Matplotlib的点、线形状、颜色以及绘制散点图
2022/04/07 Python
java开发双人五子棋游戏
2022/05/06 Java/Android