luffy之支付宝使用
复习
-直接放到项目中
-公司自己搭建文件服务器(fastdfs,ceph,minio) 小而量大的问题
-第三方存储:阿里oss,七牛云存储(sdk)
-上传文件:js--》传到存储--》返回地址---》带着地址访问咱们后端接口,把地址存入数据库
-支付宝:商户号---》营业执照---》沙箱环境
-文档---》没有营业执照申请商户号
-微信:商户号---》营业执照
-银联:sdk

1 支付宝支付测试
1.前端页面点击支付按钮
2.向后端提交下单请求
3.后端判断是否能下单,钱数对不对等
4.后台生成一个订单信息,存在订单表(待支付状态)
5.后端生成一个支付链接地址给前端
6.前端取出支付链接地址并跳转到此页面(这个地址是支付宝支付链接地址)
7.手机扫码或者登陆账号开始支付
8.支付成功后 支付宝会发两个回调地址一个给后端一个给前端
9.给后端地址是post请求(8次),通知后端已经支付成功,后端修改订单表为已支付,并回复给支付宝已收到
10.给钱端地址是get请求,前端会去订单表查询是否支付成功
-商户号
-用户号
Python支付宝开源框架:https://github.com/fzlee/alipay
使用 pip install python-alipay-sdk
-公钥,私钥:
公钥只能加密
公钥可可以给任何人
私钥只有自己有
-加密用公钥加密,解密用私钥解密
-在本地使用命令生成
-支付网站,软件生成:https://docs.open.alipay.com/291/105971
-支付宝支付的话,仅有公钥私钥不行,还需要支付宝公钥---》把咱们的公钥填入---》生成支付宝公钥
from alipay import AliPay
APP_PRIVATE_KEY_STRING = open('./pri').read()
ALIPAY_PUBLIC_KEY_STRING = open('./pub').read()
pay = AliPay(
appid='2021000119627806',
app_notify_url=None,
app_private_key_string=APP_PRIVATE_KEY_STRING,
alipay_public_key_string=ALIPAY_PUBLIC_KEY_STRING,
sign_type='RSA2',
debug=True
)
res = pay.api_alipay_trade_page_pay(
out_trade_no='123456',
total_amount=float(99),
subject='野生奥特曼',
return_url='http://127.0.0.1:8080/home',
notify_url='http://127.0.0.1:8080/home',
)
payurl = 'https://openapi.alipaydev.com/gateway.do?' + res
print(payurl)
libs
├── iPay
│ ├── __init__.py
│ ├── pem
│ │ ├── alipay_public_key.pem
│ │ ├── app_private_key.pem
│ ├── pay.py
└── └── settings.py
2 支付宝支付二次封装 文件目录如下

2.1 pay.py
from alipay import AliPay
from . import settings
pay = AliPay(
appid=settings.APP_ID,
app_notify_url=None,
app_private_key_string=settings.APP_PRIVATE_KEY_STRING,
alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_STRING,
sign_type=settings.SIGN,
debug=settings.DEBUG
)
gateway = settings.GATEWAY
2.2 settings.py
import os
APP_PRIVATE_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'app_private_key.pem')).read()
ALIPAY_PUBLIC_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'alipay_public_key.pem')).read()
APP_ID = '2021000119627806'
SIGN = 'RSA2'
DEBUG = True
GATEWAY = 'https://openapi.alipaydev.com/gateway.do' if DEBUG else 'https://openapi.alipay.com/gateway.do'
3 后台支付接口
金额也传过来,后端会判断一下
{total_amount:99,courses:[1,2,3]}
-存单个Order表,顺带存Orderdetail表----》重写create
-所有判断逻辑写到序列化类中
-
-
-
-
-
-
视图类
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from .models import Order
from utils.response import APIResponse
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from .serializer import PaySerializer
from utils.logging import logger
class OrderView(GenericViewSet, CreateModelMixin):
authentication_classes = [JSONWebTokenAuthentication, ]
permission_classes = [IsAuthenticated]
serializer_class = PaySerializer
queryset = Order.objects.all()
def create(self, request, *args, **kwargs):
try:
ser = self.get_serializer(data=request.data, context={'request': request})
ser.is_valid(raise_exception=True)
ser.save()
pay_url = ser.context.get('pay_url')
except Exception as e:
raise e
return APIResponse(pay_url=pay_url)
序列化类
from .models import Order, OrderDetail
from course.models import Course
from rest_framework import serializers
from rest_framework.validators import ValidationError
from libs.apay import pay,gateway
from django.conf import settings
class PaySerializer(serializers.ModelSerializer):
courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True)
class Meta:
model = Order
fields = ['total_amount', 'courses']
def validate(self, attrs):
self._check_price(attrs)
trade_no = self._get_trade_no()
user=self._get_user()
pay_url=self.get_pay_url(attrs,trade_no)
attrs['subject']='路飞线上课程'
attrs['out_trade_no']=trade_no
attrs['user']=user
self.context['pay_url']=pay_url
return attrs
def _check_price(self, attrs):
total_amount = attrs.get('total_amount')
courses = attrs.get('courses')
real_total_amount = 0
for course in courses:
real_total_amount += course.price
if not total_amount == real_total_amount:
raise ValidationError('价格不一致')
def _get_trade_no(self):
import uuid
trade_no = str(uuid.uuid4()).replace('-', '')
return trade_no
def _get_user(self):
user=self.context.get('request').user
return user
def get_pay_url(self,attrs,trade_no):
'''
out_trade_no='123456', # 订单号
total_amount=float(99.99), # 只有生成支付宝链接时,不能用Decimal
subject='精品内衣',
return_url='http://127.0.0.1:8080/home',
notify_url='http://127.0.0.1:8080/home',
'''
res=pay.api_alipay_trade_page_pay(
out_trade_no=trade_no,
total_amount=float(attrs.get('total_amount')),
subject='路飞线上课程',
return_url=settings.RETURN_URL,
notify_url=settings.NOTIFY_URL,
)
return gateway+res
def create(self, validated_data):
courses = validated_data.pop('courses')
order=Order.objects.create(**validated_data)
for course in courses:
OrderDetail.objects.create(course=course,order=order,price=course.price,real_price=course.price)
return order
路由
router.register('pay', views.OrderView, 'pay')
4 前端支付功能
go_pay(total_amount, course_id) {
// cookie中有token值,就是登录了
let token = this.$cookies.get('token')
if (token) {
this.$axios({
url: this.$settings.base_url + 'order/pay/',
method: 'post',
headers: {
Authorization: 'jwt ' + token,
},
data: {
'total_amount': total_amount,
'courses': [course_id,]
}
}).then(res => {
if (res.data.code == 100) {
// 跳转到支付页面
location.href = res.data.pay_url
}
})
// this.$axios.post(
// this.$settings.base_url + 'order/pay/',
// {
// 'total_amount': total_amount,
// 'courses': [course_id,]
// }, {
// headers: {
// 'Authorization': 'jwt ' + token
// },
// }
// ).then(res => {
// if (res.data.code == 100) {
// // 跳转到支付页面
// location.href = res.data.pay_url
// }
// })
} else {
this.$message({
message: "您没有登录,请先登录",
})
}
}
5 支付成功回调接口
npm run build
from rest_framework.views import APIView
from .models import Order
class PaySuccessView(APIView):
def get(self,request):
try:
out_trade_no=request.query_params.get('out_trade_no')
Order.objects.get(out_trade_no=out_trade_no,order_status=1)
except Exception as e:
raise e
return APIResponse()
def post(self,request):
try:
result_data = request.data.dict()
out_trade_no = result_data.get('out_trade_no')
signature = result_data.pop('sign')
from libs import apay
result = apay.pay.verify(result_data, signature)
if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
logger.warning('%s订单支付成功' % out_trade_no)
return Response('success')
else:
logger.error('%s订单支付失败' % out_trade_no)
except:
pass
return Response('failed')
6 git上传前端需要转成静态页面
执行:npm run build
会在目录下生成一个dist文件夹,里面的就是静态页面
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!