第19次:支付
分析
- 因要用到支付宝沙箱模拟支付功能,所以要在支付宝开放平台完成创建应用、申请密钥的相关操作
- 需要用到支付宝和应用的两对密钥,并配置到项目和支付宝开放平台。
- 在商城订单提交页面,点击“去支付”按钮,向支付宝发送支付请求,浏览器会跳转到支付宝登录页面。在登录页面需要使用沙箱账号中的买家账号和密码登录至支付宝。登录成功后,进行支付页面,用户输入支付密码完成支付;支付成功后,支付宝将自动重定向到商城的“订单支付成功”页面。
- 支付成功后,支付宝将页面重定向到settings.py定义的ALIPAY_RETURN_URL指定的回调地址,将支付结果返回。
实现
在支付宝开放平台下载支付定密钥工具,用于生成公钥和私钥。


生成密钥,加签方式:密钥,加密算法:RSA2

生成的密钥会自动保存在本地

找到沙箱页面:https://open.alipay.com/develop/sandbox/app

将刚才生成的应用公钥复制到应用公钥栏,点击“保存”按钮,将会生成支付宝公钥,复制支付宝公钥,在商城项目的payment应用下新建keys目录,并在该文件夹中创建alipay_public_key.pem和app_private_key.pem。
将支付宝公钥复制alipay_public_key.pem中,并补充如下头部和尾部信息,注意要换行。
-----BEGIN RSA PUBLIC KEY-----
公钥
-----END RSA PUBLIC KEY-----
将应用私钥复制到app_private_key.pem中,并补充如下头部和尾部信息,注意要换行。
-----BEGIN RSA PRIVATE KEY-----
私钥
-----END RSA PRIVATE KEY-----

在settings.py中配置SDK参数
ALIPAY_APPID = '2021000122674572'
ALIPAY_DEBUG = True
ALIPAY_URL = 'https://openapi.alipaydev.com/gateway.do'
ALIPAY_RETURN_URL = 'http://127.0.0.1:8000/payment/status/'
安装支付宝sdk
pip install python-alipay-sdk
在payment应用的views.py中定义PaymentView视图类,用于实现订单支付,接收页面点击“去支付”时发送的支付请求,根据order_id,创建支付对象,生成支付宝登录链接
import os
from alipay import AliPay
from django.conf import settings
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from orders.models import OrderInfo
from payment.models import Payment
from xiaoyu_mall_new.utils.response_code import RETCODE
from xiaoyu_mall_new.utils.views import LoginRequiredJSONMixin
class PaymentView(LoginRequiredJSONMixin, View):
def get(self, request, order_id):
# 获取登录用户
user = request.user
# 查询待支付订单
try:
order = OrderInfo.objects.get(order_id=order_id, user=user, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
except OrderInfo.DoesNotExist:
return HttpResponseForbidden('订单信息错误')
# 创建支付对象
alipay = AliPay(
appid=settings.ALIPAY_APPID, app_notify_url=None,
app_private_key_string=open(os.path.join(os.path.dirname(__file__), 'keys/app_private_key.pem')).read(),
alipay_public_key_string=open(os.path.join(os.path.dirname(__file__), 'keys/alipay_public_key.pem')).read(),
sign_type='RSA2',
debug=settings.ALIPAY_DEBUG,
)
# 生成支付宝登录链接
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=order_id,
total_amount=str(order.total_amount),
subject='小鱼商城%s' % order_id,
return_url=settings.ALIPAY_RETURN_URL,
)
alipay_url = settings.ALIPAY_URL + '?' + order_string
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'alipay_url': alipay_url})
配置子路由,在payment应用下创建urls.py,并增加子路由
from django.urls import path
from payment.views import PaymentView
app_name = 'payment'
urlpatterns = [
path(route='payment/<int:order_id>/', view=PaymentView.as_view()),
]
在项目urls.py中增加payment应用的子路由
path('', include('payment.urls', namespace='payment')),
支付成功后,支付宝会发起GET请求,将支付结果返回给return_url参数指定的回调地址,在payment应用中views中定义这个回调视图,完整的views.py代码为
import os
from alipay import AliPay
from django.conf import settings
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from orders.models import OrderInfo
from payment.models import Payment
from xiaoyu_mall_new.utils.response_code import RETCODE
from xiaoyu_mall_new.utils.views import LoginRequiredJSONMixin
class PaymentView(LoginRequiredJSONMixin, View):
def get(self, request, order_id):
# 获取登录用户
user = request.user
# 查询待支付订单
try:
order = OrderInfo.objects.get(order_id=order_id, user=user, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
except OrderInfo.DoesNotExist:
return HttpResponseForbidden('订单信息错误')
# 创建支付对象
alipay = AliPay(
appid=settings.ALIPAY_APPID, app_notify_url=None,
app_private_key_string=open(os.path.join(os.path.dirname(__file__), 'keys/app_private_key.pem')).read(),
alipay_public_key_string=open(os.path.join(os.path.dirname(__file__), 'keys/alipay_public_key.pem')).read(),
sign_type='RSA2',
debug=settings.ALIPAY_DEBUG,
)
# 生成支付宝登录链接
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=order_id,
total_amount=str(order.total_amount),
subject='小鱼商城%s' % order_id,
return_url=settings.ALIPAY_RETURN_URL,
)
alipay_url = settings.ALIPAY_URL + '?' + order_string
return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'alipay_url': alipay_url})
class PaymentStatusView(View):
# 保存订单支付结果
def get(self, request):
# 获取到所有查询字符串参数
query_dict = request.GET
# 转换成字典类型
data = query_dict.dict()
# 移除sign
signature = data.pop('sign')
alipay = AliPay(
appid=settings.ALIPAY_APPID, app_notify_url=None,
app_private_key_string=open(
os.path.join(os.path.dirname(__file__)), 'keys/app_private_key.pem').read(),
alipay_public_key_string=open(
os.path.join(os.path.dirname(__file__), 'keys/alipay_public_key.pem')).read(),
sign_type='RSA2',
debug=settings.ALIPAY_DEBUG,
)
success = alipay.verify(data, signature)
if success:
order_id = data.get('out_trade_no')
trade_id = data.get('trade_no')
Payment.objects.create(
order_id=order_id, trade_id=trade_id,
)
OrderInfo.objects.filter(order_id=order_id, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']).update(
status=OrderInfo.ORDER_STATUS_ENUM['UNCOMMENT']
)
context = {'trade_id': trade_id}
return render(request, 'pay_success.html', context)
else:
return redirect(reverse('users:myorderinfo'))
8781

被折叠的 条评论
为什么被折叠?



