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中PDB模块中的命令来调试Python代码的教程
Mar 30 Python
python各种语言间时间的转化实现代码
Mar 23 Python
Python 通过URL打开图片实例详解
Jun 01 Python
Python实现读取txt文件并画三维图简单代码示例
Dec 09 Python
使用NumPy和pandas对CSV文件进行写操作的实例
Jun 14 Python
Django csrf 两种方法设置form的实例
Feb 03 Python
python-Web-flask-视图内容和模板知识点西宁街
Aug 23 Python
python解释器spython使用及原理解析
Aug 24 Python
Python SELENIUM上传文件或图片实现过程
Oct 28 Python
pytorch dataloader 取batch_size时候出现bug的解决方式
Feb 20 Python
python 进程池pool使用详解
Oct 15 Python
Python-openpyxl表格读取写入的案例详解
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求最大子序列和的算法实现
2011/06/24 PHP
PHP连接和操作MySQL数据库基础教程
2014/09/29 PHP
php实现的递归提成方案实例
2015/11/14 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
2016/06/13 PHP
HR vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
javascript在事件监听方面的兼容性小结
2010/04/07 Javascript
JS冒泡事件的快速解决方法
2013/12/16 Javascript
ztree获取当前选中节点子节点id集合的方法
2015/02/12 Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
2015/03/01 Javascript
jQuery实现伸展与合拢panel的方法
2015/04/30 Javascript
jQuery+formdata实现上传进度特效遇到的问题
2016/02/24 Javascript
js 动态添加元素(div、li、img等)及设置属性的方法
2016/07/19 Javascript
jQuery事件绑定方法学习总结(推荐)
2016/11/21 Javascript
node.js实现的装饰者模式示例
2017/09/06 Javascript
JS获取指定月份的天数两种实现方法
2018/06/22 Javascript
详解基于Vue-cli搭建的项目如何和后台交互
2018/06/29 Javascript
Angular中的ng-template及angular 使用ngTemplateOutlet 指令的方法
2018/08/08 Javascript
详解VUE里子组件如何获取父组件动态变化的值
2018/12/26 Javascript
Vue最新防抖方案(必看篇)
2019/10/30 Javascript
Python pass 语句使用示例
2014/03/11 Python
Python列表生成器的循环技巧分享
2015/03/06 Python
Python入门学习之字符串与比较运算符
2015/10/12 Python
Python装饰器使用你可能不知道的几种姿势
2019/10/25 Python
详解pandas绘制矩阵散点图(scatter_matrix)的方法
2020/04/23 Python
解决python虚拟环境切换无效的问题
2020/04/30 Python
python属于解释语言吗
2020/06/11 Python
python用什么编辑器进行项目开发
2020/06/17 Python
python中字典增加和删除使用方法
2020/09/30 Python
Django haystack实现全文搜索代码示例
2020/11/28 Python
Java基础类库面试题
2013/09/04 面试题
建筑工程管理专业自荐信范文
2013/12/28 职场文书
2015新年寄语(一句话)
2014/12/08 职场文书
求职自我评价范文
2015/03/09 职场文书
防暑降温通知书
2015/04/27 职场文书
全国法制宣传日活动总结
2015/05/05 职场文书
Python使用BeautifulSoup4修改网页内容
2022/05/20 Python