Django1.11配合uni-app發(fā)起微信支付的實(shí)現(xiàn)
Django1.11配合uni-app發(fā)起微信支付!
經(jīng)過(guò)三天的斷斷續(xù)續(xù)的奮戰(zhàn),我終于是干動(dòng)了微信支付。為了以后不忘記,現(xiàn)在來(lái)一篇教程,來(lái)來(lái)來(lái),開干?。?!

一、準(zhǔn)備階段
1、準(zhǔn)備階段我們需要去微信官網(wǎng)申請(qǐng)一個(gè)小程序或者公眾號(hào)。獲得AppID和AppSecret。

2、去微信商戶平臺(tái) 成為商家,開通JSAPI用來(lái)獲得商戶號(hào)和自己配置的鑰匙。然后再商戶平臺(tái)上面綁定小程序appid。

(點(diǎn)擊下面圖片進(jìn)入官方鏈接?。?/p>
在配置里面配置一個(gè)自己的key,需要記住后臺(tái)開發(fā)的時(shí)候需要!

關(guān)聯(lián)后即可在小程序管理頁(yè)面開通微信支付!

到此,準(zhǔn)備階段完成!
二、梳理流程
在這里我大概寫一下流程:首先我們?cè)谇岸税l(fā)起微信登陸,此時(shí)微信會(huì)給我們返回一個(gè)openid,這個(gè)openid一定要留存在某一個(gè)位置。然后前段發(fā)起微信支付,向后端發(fā)送數(shù)據(jù)請(qǐng)求,后端對(duì)結(jié)合前段的數(shù)據(jù)向微信方面發(fā)送一個(gè)請(qǐng)求,請(qǐng)求相關(guān)數(shù)據(jù),得到相關(guān)數(shù)據(jù)之后把數(shù)據(jù)發(fā)送給前段,前段收到數(shù)據(jù),利用微信接口再向微信指定連接發(fā)送請(qǐng)求,微信返回請(qǐng)求,即可!這個(gè)就是全流程,很多人肯定已經(jīng)懵了。沒事,咱一步一步來(lái),別步子跨大了——扯到蛋了!

以上就是數(shù)據(jù)處理階段大概流程!
三、代碼實(shí)現(xiàn)
0、用戶登錄根據(jù)用戶code獲取openid
uni.login({
provider: 'weixin',
success: function(loginRes) {
let code = loginRes.code;
if (!_this.isCanUse) {
//非第一次授權(quán)獲取用戶信息
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
//獲取用戶信息后向調(diào)用信息更新方法
_this.nickName = infoRes.userInfo.nickName; //昵稱
_this.avatarUrl = infoRes.userInfo.avatarUrl; //頭像
_this.updateUserInfo();//調(diào)用更新信息方法
}
});
}
//2.將用戶登錄code傳遞到后臺(tái)置換用戶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("新注冊(cè)的用戶!")
_this.OpenId = res.data.openid;
} else{
_this.OpenId = res.data.openid;
console.log("注冊(cè)過(guò)的用戶!開始設(shè)置本地緩存!")
console.log(res.data[0].id)
if ( res.data[0].id ) {
//這里獲得登陸狀態(tài),然后根據(jù)登陸狀態(tài)來(lái)改變用戶按鈕信息!?。?!
} else{
};
_this.user_id = res.data[0].id
uni.setStorage({
key: 'user',
data: res.data,
success: function () {
console.log('設(shè)置緩存成功');
}
});
// _this.gotoshopping()
// uni.reLaunch({//信息更新成功后跳轉(zhuǎn)到小程序首頁(yè)
// url: '/pages/shopping/shopping'
// });
}
//openId、或SessionKdy存儲(chǔ)//隱藏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、首先需要?jiǎng)?chuàng)建一個(gè)confige.py的配置文件!然后寫路由,讓前端找到“門”在哪里!
config.py
# 微信支付的配置參數(shù) client_appid = 'xxxxxxxxxxxxxx' # 小程序appid client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx' # 小程序secret Mch_id = 'xxxxxxxxxxx' # 商戶號(hào) 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) #這個(gè)就是微信支付的接口
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、然后創(chuàng)建邏輯文件,獲取數(shù)據(jù)請(qǐng)求數(shù)據(jù)返回?cái)?shù)據(jù)!
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
# 生成簽名的函數(shù)
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)
# 處理函數(shù),對(duì)參數(shù)按照key=value的格式,并按照參數(shù)名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()
# 生成隨機(jī)字符串
def getNonceStr():
import random
data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
nonce_str = ''.join(random.sample(data, 30))
return nonce_str
# 生成商品訂單號(hào)
def getWxPayOrdrID():
date = datetime.datetime.now()
# 根據(jù)當(dāng)前系統(tǒng)時(shí)間來(lái)生成商品訂單號(hào)。時(shí)間精確到微秒
payOrdrID = date.strftime("%Y%m%d%H%M%S%f")
return payOrdrID
# 獲取全部參數(shù)信息,封裝成xml
def get_bodyData(openid, client_ip, price):
body = 'Mytest' # 商品描述
notify_url = 'https://127.0.0.1:8000/payOrder/' # 支付成功的回調(diào)地址 可訪問(wèn) 不帶參數(shù)
nonce_str = getNonceStr() # 隨機(jī)字符串
out_trade_no = getWxPayOrdrID() # 商戶訂單號(hào)
total_fee = str(price) # 訂單價(jià)格 單位是 分
# 獲取簽名
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>' # 商戶號(hào)
bodyData += '<nonce_str>' + nonce_str + '</nonce_str>' # 隨機(jī)字符串
bodyData += '<notify_url>' + notify_url + '</notify_url>' # 支付成功的回調(diào)地址
bodyData += '<openid>' + openid + '</openid>' # 用戶標(biāo)識(shí)
bodyData += '<out_trade_no>' + out_trade_no + '</out_trade_no>' # 商戶訂單號(hào)
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()
# 統(tǒng)一下單支付接口
def payOrder(request):
import time
# 獲取價(jià)格,和用戶是誰(shuí)
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
# 請(qǐng)求微信的url
url = order_url
# 拿到封裝好的xml數(shù)據(jù)
body_data = get_bodyData(openid, client_ip, price)
# 獲取時(shí)間戳
timeStamp = str(int(time.time()))
# 請(qǐng)求微信接口下單
respone = requests.post(url, body_data.encode("utf-8"), headers={'Content-Type': 'application/xml'})
# 回復(fù)數(shù)據(jù)為xml,將其轉(zhuǎn)為字典
content = xml_to_dict(respone.content)
print(content)
# 返回給調(diào)用函數(shù)的數(shù)據(jù)
ret = {"state": 1000}
if content["return_code"] == 'SUCCESS':
# 獲取預(yù)支付交易會(huì)話標(biāo)識(shí)
prepay_id = content.get("prepay_id")
# 獲取隨機(jī)字符串
nonceStr = content.get("nonce_str")
# 獲取paySign簽名,這個(gè)需要我們根據(jù)拿到的prepay_id和nonceStr進(jìn)行計(jì)算簽名
paySign = get_paysign(prepay_id, timeStamp, nonceStr)
# 封裝返回給前端的數(shù)據(jù)
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、前段獲取后端返回的數(shù)據(jù)給微信再次發(fā)送數(shù)據(jù)請(qǐng)求?。òc(diǎn)擊的時(shí)候往后端發(fā)送數(shù)據(jù)處理請(qǐng)求)
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));
// 支付成功,給后臺(tái)發(fā)送數(shù)據(jù),保存訂單
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
// 支付失敗,給后臺(tái)發(fā)送數(shù)據(jù),保存訂單
}
});
},
fail: (res) => {
console.log("fail")
console.log(res)
},
complete: () => {}
});
}
至此相信大家也就會(huì)了。
附上我的目錄結(jié)構(gòu)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的方法示例
這篇文章主要介紹了Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的方法,結(jié)合實(shí)例形式分析了Python中基于給定優(yōu)先級(jí)進(jìn)行隊(duì)列元素排序的相關(guān)操作技巧,需要的朋友可以參考下2018-02-02
人工智能學(xué)習(xí)Pytorch張量數(shù)據(jù)類型示例詳解
這篇文章主要為大家介紹了人工智能學(xué)習(xí)Pytorch張量數(shù)據(jù)類型的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11
python實(shí)現(xiàn)在一個(gè)畫布上畫多個(gè)子圖
今天小編就為大家分享一篇python實(shí)現(xiàn)在一個(gè)畫布上畫多個(gè)子圖,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
如何將matlab數(shù)據(jù)導(dǎo)入到Python中使用
這篇文章主要介紹了如何將matlab數(shù)據(jù)導(dǎo)入到Python中使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
Python 保存矩陣為Excel的實(shí)現(xiàn)方法
今天小編就為大家分享一篇Python 保存矩陣為Excel的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
Python中的類的定義和對(duì)象的創(chuàng)建方法
object?是?Python?為所有對(duì)象提供的?基類,提供有一些內(nèi)置的屬性和方法,可以使用?dir?函數(shù)查看,這篇文章主要介紹了Python中的類的定義和對(duì)象的創(chuàng)建,需要的朋友可以參考下2022-11-11
PyCharm2021最新激活碼+激活碼補(bǔ)丁(親測(cè)最新版PyCharm2021.3激活成功)
這篇文章主要介紹了PyCharm2021最新激活碼+激活碼補(bǔ)丁,親測(cè)最新版PyCharm2021.3激活成功,PyCharm2020激活成功2020-09-09


