Django payment processing:有哪些推荐的 Python/Django 支付处理库?
结论
Django 项目一般不需要一个「包办所有支付渠道」的通用库。具体选什么,主要取决于支付服务商和业务复杂度:
- 使用 Stripe 时,优先选择官方 Python SDK
stripe。如果还要同步订阅、客户和账单等对象,可以评估dj-stripe。 - 如果需要统一接入多个支付服务商,可以评估
django-payments,但要先确认它是否支持目标渠道和所需功能。 - 接入支付宝、微信支付或其他本地渠道时,优先选择支付服务商的官方 SDK,或者维护活跃、文档完整的渠道专用库。
- 只使用 PayPal 等单一渠道时,通常直接调用该渠道的官方 REST API/SDK,比依赖老旧的 Django 封装更可靠。
支付是高风险模块。选型时,维护状态、Webhook 支持、幂等处理和签名验证,比 API 是否看起来简单更值得关注。
常见选择
官方 Python SDK
如果已经确定支付服务商,官方 SDK 通常是首选。例如:
pip install stripe
它的主要优势是:
- API 能力通常覆盖得最完整;
- 新功能和安全变更跟进更及时;
- 官方文档、错误码和示例更容易相互对应;
- 业务不会过度依赖第三方 Django 数据模型。
相应的代价是,你需要自行设计订单状态、支付记录、Webhook 日志和退款流程。
dj-stripe
dj-stripe 适合深度使用 Stripe 的 Django 项目,尤其适用于订阅、客户和账单类业务。它能将部分 Stripe 对象同步到 Django 数据库,并提供配套的数据模型和 Webhook 集成。
不过,它不能替代 Stripe 官方 SDK。创建和确认支付、调用 Stripe API 时,底层仍然会用到 stripe SDK。引入之前,需要检查项目当前的维护状态、兼容的 Django/Python 版本,以及它覆盖了哪些 Stripe API 对象。
django-payments
django-payments 提供了一套相对统一的支付抽象,适合需要通过类似接口切换或组合多个支付后端的项目。
这类抽象层也有明显限制。不同渠道对预授权、退款、订阅、分账和异步通知的定义并不完全相同。一旦业务用到某个渠道的专有能力,最终仍可能需要调用该渠道的原生 API。
采用前至少要确认:
- 是否支持目标支付渠道;
- 是否支持退款、订阅和重复支付;
- 如何处理 Webhook 或异步通知;
- 项目是否仍在维护;
- 是否兼容当前使用的 Django 和 Python 版本。
不要只看包名或旧教程就判断它是否可用。
一个基础的 Stripe PaymentIntent 实现
下面的示例展示了如何在 Django 服务端创建 PaymentIntent。这里只保留核心结构,生产环境还需要加入登录校验、订单模型、异常处理和日志。
安装 SDK:
pip install stripe
在环境变量中保存密钥:
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
Django 配置:
# settings.py
import os
STRIPE_SECRET_KEY = os.environ["STRIPE_SECRET_KEY"]
STRIPE_WEBHOOK_SECRET = os.environ["STRIPE_WEBHOOK_SECRET"]
创建 PaymentIntent:
# views.py
import stripe
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.http import require_POST
stripe.api_key = settings.STRIPE_SECRET_KEY
@require_POST
def create_payment(request):
# 金额必须从服务端订单数据读取,不能信任客户端传入的金额。
order_id = "ORDER-2026-0001"
amount = 19900 # 以最小货币单位表示;这里代表 199.00 CNY
intent = stripe.PaymentIntent.create(
amount=amount,
currency="cny",
metadata={"order_id": order_id},
idempotency_key=f"payment-intent:{order_id}",
)
return JsonResponse({
"client_secret": intent.client_secret,
})
这里需要注意两点:
amount应由服务端根据订单重新计算,不能直接使用浏览器提交的金额。idempotency_key应绑定一次确定的业务操作,避免网络重试产生重复请求。
不同支付渠道、支付方式和账户所在地区可能存在额外限制,实际参数应以所选服务商当前的文档为准。
使用 Webhook 更新订单状态
不能只通过前端跳转页面判断支付是否成功。用户可能关闭页面,网络也可能中断,前端返回值还可能被伪造。订单的最终状态应由经过签名验证的 Webhook 更新。
# views.py
import stripe
from django.conf import settings
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
@csrf_exempt
@require_POST
def stripe_webhook(request):
payload = request.body
signature = request.headers.get("Stripe-Signature", "")
try:
event = stripe.Webhook.construct_event(
payload=payload,
sig_header=signature,
secret=settings.STRIPE_WEBHOOK_SECRET,
)
except (ValueError, stripe.error.SignatureVerificationError):
return HttpResponse(status=400)
if event["type"] == "payment_intent.succeeded":
payment_intent = event["data"]["object"]
order_id = payment_intent.get("metadata", {}).get("order_id")
if order_id:
# 在数据库事务中更新订单。
# 更新前还应核对金额、币种、商户账户和当前订单状态。
mark_order_as_paid(
order_id=order_id,
provider_payment_id=payment_intent["id"],
)
return HttpResponse(status=200)
mark_order_as_paid() 应设计为幂等操作。同一个事件即使被投递多次,也只能完成一次业务入账。建议单独保存支付服务商的事件 ID,并通过数据库唯一约束避免重复处理。
推荐的实施步骤
1. 先确定业务能力
先列出真正需要的功能,再选择库:
- 一次性支付;
- 订阅和自动续费;
- 全额或部分退款;
- 预授权与后续扣款;
- 多币种;
- 分账或平台型支付;
- 支付状态查询与对账。
如果只需要单一渠道的一次性支付,官方 SDK 往往就够用了。只有确实需要统一模型或本地对象同步时,才有必要引入 Django 集成库。
2. 建立自己的支付数据模型
不要让业务订单直接依赖第三方 SDK 对象。至少应保存:
- 内部订单号;
- 支付渠道;
- 渠道侧支付 ID;
- 请求金额与币种;
- 支付状态;
- 已退款金额;
- 创建、成功和退款时间;
- Webhook 事件 ID。
金额建议用整数形式的最小货币单位保存,也可以使用 Decimal。不要用 float 计算支付金额。
3. 服务端创建支付请求
价格、优惠、税费和运费都应由服务端计算。客户端只需提交商品、订单或支付方式等必要标识。
4. 通过 Webhook 确认结果
收到通知后,必须验证签名,并重新核对订单号、金额、币种和支付状态。发货、充值或开通权限等操作应放在数据库事务中,同时保证可以重复执行。
5. 完整测试异常路径
除了支付成功,还要测试:
- 用户取消支付;
- 支付超时;
- 重复提交;
- Webhook 重复或乱序到达;
- 服务端处理 Webhook 时失败;
- 部分退款和重复退款;
- 金额或币种不匹配;
- 测试环境与生产环境密钥混用。
注意事项
- 密钥只能保存在服务端环境变量或密钥管理系统中,不要提交到 Git,也不要发送给浏览器。
- Webhook 地址通常需要豁免 Django 的 CSRF 校验,但仍然必须验证支付服务商的签名。
- 不要根据前端显示的「支付成功」直接发货或充值。
- 敏感的支付卡数据应尽量交给支付服务商托管的页面或前端组件收集,避免进入自己的服务器。
- 库的维护状态和兼容性会变化。安装前要检查发布记录、问题列表、支持的 Python/Django 版本,以及支付服务商 API 的覆盖范围。
- 支付成功、退款成功和业务履约是不同的状态,不要用一个布尔字段表示整个流程。
如果没有明确的多渠道抽象需求,可以从支付服务商的官方 Python SDK 开始,在 Django 中自行维护订单、支付记录和幂等的 Webhook 处理。这样写的代码会多一些,但各部分边界清楚,排查资金状态问题也更容易。
备注:内容仅供参考。
