Django实现支付宝沙箱操作
环境即所需模块
- Django == 3.1.0
- python == 3.7.4
- python-alipay-sdk=2.0.1
所需
- 下载模块 python-alipay-sdk=2.0.1
- 文档 非官方支付宝 Python SDK: https://github.com/fzlee/alipay/blob/master/README.zh-hans.md#alipay.trade.page.pay
沙箱环境配置
- 在支付宝开放平台---->开发者中心—>开发服务---->沙箱
- RSA2密钥生成并上传 参考官方地址:https://opendocs.alipay.com/open/291/105971
- 下载支付宝开放平台开发助手下载地址https://opendocs.alipay.com/open/291/introduce下载后生成秘钥[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iAJ4s57z-1602600230093)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013215751437.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLkaGka3-1602600315452)(C:%5CUsers%5CASUS%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20201013215646909.png#pic_center)]
)
4.将应用公钥复制到支付宝中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pm1umRDQ-1602600230099)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013220238000.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIM2Wwqr-1602600230101)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013220309533.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CZRSx4tY-1602600230104)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013220359867.png)]
5.配置app中支付宝公钥 开发助手秘钥
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hzEeNDd6-1602600230107)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013220610210.png)]
- 在Django的app中创建文件夹置放支付宝公钥[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bg9hMEFa-1602600230111)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013221108217.png)]
- 在Django的app中创建文件夹置放开放平台私钥[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0aGqpG4B-1602600230112)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013221548593.png)]
Django Models
# 支付状态表 class Status(BaseModel): name = models.CharField(max_length=32) class Meta: db_table = 'status' # 支付表 class Order(BaseModel): out_trade_no = models.CharField(max_length=60) trada_no = models.CharField(max_length=60, null=True, blank=True) goods = models.ForeignKey(Goods, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) goods_num = models.IntegerField() status = models.ForeignKey(Status, on_delete=models.CASCADE) class Meta: db_table = 'order'
Django Views配置
- 所需的包import uuid import redis from app01.views import login_serializer from alipay import AliPay, AliPayConfig123
# 绝对路径打开文件 {}代表从这里往前 app_private_key_string = open('{}\\app02\\alipay_key\\app_private_key'.format(settings.BASE_DIR)).read() alipay_public_key_string = open('{}\\app02\\alipay_key\\alipay_public'.format(settings.BASE_DIR)).read()12
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TU8ck5hJ-1602600230116)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013222520219.png)]
alipay = AliPay( appid="2016102500759596", app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=alipay_public_key_string, sign_type="RSA2", # RSA 或者 RSA2 debug=True, # 默认False config=AliPayConfig(timeout=15) # 可选, 请求超时时间 )123456789
3.注释的代码可以去掉
# 支付 class AlipayView(APIView): def post(self, request): # print(request.data) token = request.data.get('token') count = request.data.get('count') goods_info = request.data.get('goods_info') # print(goods_info) # 订单号 uuid唯一不重复 out_trade_no = str(uuid.uuid4()) # 订单金额初始 total_amount = 0 user_info = login_serializer.loads(token) user_id = user_info.get('user_id') # 判断是否是多个id 用,号分割 if goods_info.find(',') != -1: order_list = [] for i in goods_info.split(','): print(i) # 循环输出id # # 获取购物车商品数量 # goods_count = r3.hget(user_id, i).decode() # # get到等于i的商品 # goods_obj = Goods.objects.get(pk=i) # # 计算总价 # total_amount += int(goods_obj.price) * int(goods_count)\ # 列表添加类型 order_list.append(Order( out_trade_no=out_trade_no, goods_id=i, user_id=user_id, goods_num=count, status_id=1, )) print(order_list) # 批量添加 列表 ser = Order.objects.bulk_create(order_list) # ser.save() else: # print(r3.hget(user_id, goods_info)) # goods_count = r3.hget(user_id, goods_info).decode() # goods_obj = Goods.objects.get(pk=goods_info) # total_amount += int(goods_obj.price) * int(goods_count) # print(total_amount) # 单个添加 ser = OrderModelSer(data={ "out_trade_no": out_trade_no, "goods": goods_info, "user": user_id, "goods_num": count, "status": 1 }) if ser.is_valid(): ser.save() else: print(ser.errors) # 主题 subject = "京东" # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string order_string = alipay.api_alipay_trade_page_pay( out_trade_no=out_trade_no, total_amount=count, subject=subject, return_url="http://127.0.0.1:8000/app02/callback_alipay", notify_url="http://127.0.0.1:8000/app02/callback_alipay" # 可选, 不填则使用默认notify url ) # 拼接的数据 # print(order_string) pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string # 带参数跳转的路由 # print(pay_url) return Response({'pay_url': pay_url, 'msg': 'OK', "code": 200})12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6WYKp5g-1602600230119)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013223018379.png)]
4.0
# 支付完回调地址 class CallBackAlipayView(APIView): def get(self, request): print(request.query_params) print("------------------------------") # 判断是否有数据 if request.query_params.get("sign"): # for i in request.query_params.get("out_trade_no"): # print(request.query_params.get("out_trade_no")) # 获取订单号 queryset = Order.objects.get(out_trade_no=request.query_params.get("out_trade_no")) # 修改订单状态为已购买 局部修改 ser = OrderModelSer(instance=queryset, data={"status": 2}, partial=True) if ser.is_valid(): ser.save() else: print(ser.errors) return Response({'msg': 'OK', "data": request.query_params})1234567891011121314151617181920
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AFbrRopL-1602600230122)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201013223126443.png)]
调用接口
addcart() { let data = new FormData(); data.append("token", sessionStorage.getItem("token")) data.append("goods_info", this.check) data.append("count", this.count2) axios({ url: "http://127.0.0.1:8000/app02/alipay", method: 'post', data: data }).then(res => { console.log(res.data) if (res.data.code === 200) { window.location.href = res.data.pay_url } }) },12345678910111213141516
1
调用的页面
<template> <div> <div id="app"> <div class="header_con"> <div class="header"> <div class="welcome fl">欢迎来到美多商城!</div> <div class="fr"> <div v-if="username" class="login_btn fl"> 欢迎您:<em>{ { username }}</em> <span>|</span> <a @click="logout">退出</a> </div> <div v-else class="login_btn fl"> <a href="login.html">登录</a> <span>|</span> <a href="register.html">注册</a> </div> <div class="user_link fl"> <span>|</span> <a href="user_center_info.html">用户中心</a> <span>|</span> <a href="cart.html">我的购物车</a> <span>|</span> <a href="user_center_order.html">我的订单</a> </div> </div> </div> </div> <div class="search_bar clearfix"> <a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a> <div class="sub_page_name fl">| 购物车</div> <form method="get" action="/search.html" class="search_con fr mt40"> <input type="text" class="input_text fl" name="q" placeholder="搜索商品"> <input type="submit" class="input_btn fr" name="" value="搜索"> </form> </div> <div class="total_count">全部商品<em>{ {cart.length}}</em>件</div> <ul class="cart_list_th clearfix"> <li class="col01">商品名称</li> <li class="col03">商品价格</li> <li class="col04">数量</li> <li class="col05">小计</li> <li class="col06">操作</li> </ul> <ul class="cart_list_td clearfix" v-for="(sku,index) in cart"> <li class="col01"><input type="checkbox" name="" v-model="check" :value="sku.id" @click="checkbox(sku.id,sku.count,sku.price)"></li> <li class="col02"><img :src="'http://127.0.0.1:8000'+sku.img"></li> <li class="col03">{ { sku.name }}</li> <li class="col05">{ { sku.price }}元</li> <li class="col06"> <div class="num_add"> <a @click="on_add(sku.id)" class="add fl">+</a> <input v-model="sku.count" @focus="origin_input=sku.count" @blur="on_input(index)" type="text" class="num_show fl"> <a @click="on_minus(sku.id)" class="minus fl">-</a> </div> </li> <li class="col07">{ {sku.price * sku.count}}元</li> <li class="col08"><a @click="del(sku.id)">删除</a></li> </ul> <ul class="settlements"> <li class="col01"><input type="checkbox" @click="check_count" v-model="isChecked"></li> <li class="col02">全选</li> <li class="col03">合计(不含运费):<span>¥</span><em>{ {count2}}</em><br>共计<b>{ {total_selected_count}}</b>件商品 </li> <li class="col04"><a @click="addcart">去结算</a></li> </ul> </div> <fooder></fooder> </div> </template> <script> import axios from 'axios' import fooder from '../components/Fooder' export default { name: "Cart", data() { return { cart: [ ], check: [], username: "", total_selected_amount: "", total_selected_count: "", on_selected_all: "", selected_all: "", count2: 0, isChecked: false, } }, components: { 'fooder': fooder }, methods: { del(goods_id) { let data = new FormData(); data.append("token", sessionStorage.getItem("token")) data.append("goods_id", goods_id) axios({ url: 'http://127.0.0.1:8000/app02/delcart', method: 'delete', data: data }).then(res => { console.log(res) this.$router.go(0) }) }, addcart() { let data = new FormData(); data.append("token", sessionStorage.getItem("token")) data.append("goods_info", this.check) data.append("count", this.count2) axios({ url: "http://127.0.0.1:8000/app02/alipay", method: 'post', data: data }).then(res => { console.log(res.data) if (res.data.code === 200) { window.location.href = res.data.pay_url } }) }, on_add(goods_id) { let data = new FormData(); data.append("token", sessionStorage.getItem("token")) data.append("goods_id", goods_id) axios({ url: 'http://127.0.0.1:8000/app02/addcart', method: 'post', data: data }).then(res => { console.log(res) this.$router.go(0) }) }, on_minus(goods_id) { let data = new FormData(); data.append("token", sessionStorage.getItem("token")) data.append("goods_id", goods_id) axios({ url: 'http://127.0.0.1:8000/app02/minuscart', method: 'post', data: data }).then(res => { console.log(res) this.$router.go(0) }) }, show() { axios({ url: 'http://127.0.0.1:8000/app02/showcart', method: 'get', params: {"token": sessionStorage.getItem("token")} }).then(res => { console.log(res) this.cart = res.data.data }) }, //全选并调用总价 check_count() { //默认值为false this.count2 = 0; this.check = []; if (this.isChecked) { this.check = [] } else { this.cart.forEach(item => { console.log(item.id); this.check.push(item.id); this.count() }) } }, //计算总价 count() { // let count = 0 this.count2 = 0 for (let i in this.cart) { console.log(this.cart[i]) this.count2 += this.cart[i].price * this.cart[i].count } }, //计算单选框 checkbox(gid, count, price) { //第一次执行都为空 false console.log(this.check) if (this.check.includes(gid)) { // 包含则说明已经选中 再次点击删除 false 并减去相应的价格 this.count2 -= count * price this.check.splice(this.check.indexOf(gid), 1) } else { //推送 也就是添加 变为true this.check.push[gid] //计算总价 选中相加 this.count2 += count * price } }, }, created() { this.show() } } </script> <style scoped> </style> 次点击删除 false 并减去相应的价格 this.count2 -= count * price this.check.splice(this.check.indexOf(gid), 1) } else { //推送 也就是添加 变为true this.check.push[gid] //计算总价 选中相加 this.count2 += count * price } }, }, created() { this.show() } } </script> <style scoped> </style>
PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取
完整代码可以点击下方链接获取~