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中下划线的使用方法
Mar 27 Python
Django的URLconf中使用缺省视图参数的方法
Jul 18 Python
利用pyinstaller或virtualenv将python程序打包详解
Mar 22 Python
python根据unicode判断语言类型实例代码
Jan 17 Python
python和shell获取文本内容的方法
Jun 05 Python
python实现各种插值法(数值分析)
Jul 30 Python
python3 enum模块的应用实例详解
Aug 12 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
Oct 16 Python
Python统计学一数据的概括性度量详解
Mar 03 Python
使用jupyter notebook直接打开.md格式的文件
Apr 10 Python
协程Python 中实现多任务耗资源最小的方式
Oct 19 Python
Python常用扩展插件使用教程解析
Nov 02 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
PHP控制网页过期时间的代码
2008/09/28 PHP
zend optimizer在wamp的基础上安装图文教程
2013/10/26 PHP
phpMyAdmin自动登录和取消自动登录的配置方法
2014/05/12 PHP
Laravel中扩展Memcached缓存驱动实现使用阿里云OCS缓存
2015/02/10 PHP
php源码的安装方法和实例
2019/09/26 PHP
php抽象方法和普通方法的区别点总结
2019/10/13 PHP
php使用redis的有序集合zset实现延迟队列应用示例
2020/02/20 PHP
Laravel相关的一些故障解决
2020/08/19 PHP
学习ExtJS fit布局使用说明
2009/10/08 Javascript
关于JavaScript定义类和对象的几种方式
2010/11/09 Javascript
jQuery 滑动方法slideDown向下滑动元素
2014/01/16 Javascript
js获取下拉列表的值和元素个数示例
2014/05/07 Javascript
javascript引擎长时间独占线程造成卡顿的解决方案
2014/12/03 Javascript
5种处理js跨域问题方法汇总
2014/12/04 Javascript
使用AngularJS创建单页应用的编程指引
2015/06/19 Javascript
易被忽视的js事件问题总结
2016/05/14 Javascript
Bootstrap弹出带合法性检查的登录框实例代码【推荐】
2016/06/23 Javascript
使用UrlConnection实现后台模拟http请求的简单实例
2017/01/04 Javascript
基于jQuery实现咖啡订单管理简单应用
2017/02/10 Javascript
使用puppeteer破解极验的滑动验证码
2018/02/24 Javascript
javascript验证form表单数据的案例详解
2019/03/25 Javascript
Vue 基于 vuedraggable 实现选中、拖拽、排序效果
2020/05/18 Javascript
python循环监控远程端口的方法
2015/03/14 Python
Python文件及目录操作实例详解
2015/06/04 Python
Python requests模块基础使用方法实例及高级应用(自动登陆,抓取网页源码)实例详解
2020/02/14 Python
django实现模板中的字符串文字和自动转义
2020/03/31 Python
Python requests模块session代码实例
2020/04/14 Python
联想马亚西亚官方网站:Lenovo Malaysia
2018/09/19 全球购物
size?爱尔兰官方网站:英国伦敦的球鞋精品店
2019/03/31 全球购物
北京某公司的.net笔试题
2014/03/20 面试题
工程造价与管理专业应届生求职信
2013/11/23 职场文书
入团者的自我评价分享
2013/12/02 职场文书
迎元旦广播稿
2014/02/22 职场文书
请病假条范文
2015/08/17 职场文书
大学生村官工作心得体会
2016/01/23 职场文书
MySQL 不等于的三种使用及区别
2021/06/03 MySQL