
本教程详细介绍了如何在django项目中集成stripe支付,以支持单品购买和多商品订单支付。内容涵盖了stripe checkout会话的创建、django模型与视图的实现、url路由配置以及前端javascript集成。同时,文章还提供了针对常见404错误和代码逻辑问题的排查与优化建议,旨在帮助开发者构建稳定可靠的电商支付系统。
在现代Web应用中,集成第三方支付平台是实现电子商务功能的关键一环。Stripe以其强大的API和灵活的集成方式,成为许多开发者的首选。本教程将以一个Django项目为例,展示如何利用Stripe Checkout实现商品和订单的支付流程。
为了处理商品和订单,我们需要定义相应的Django模型。
models.py
from django.db import models
class Item(models.Model):
"""
商品模型,包含名称、描述和价格。
"""
name = models.CharField(max_length=100)
description = models.TextField()
price = models.IntegerField(default=0) # 价格以美分存储,方便Stripe处理
def __str__(self):
return self.name
def display_price(self):
"""格式化显示价格为美元"""
return "{0:.2f}".format(self.price / 100) # 注意:这里假设price是美分,显示时除以100
class Order(models.Model):
"""
订单模型,包含客户信息、创建时间及关联的商品。
"""
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
address = models.CharField(max_length=250)
postal_code = models.CharField(max_length=20)
city = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
items = models.ManyToManyField(Item, through='OrderItem') # 通过中间模型关联商品
class Meta:
ordering = ('-created_at',)
def __str__(self):
return f'Order {self.id} | {self.created_at.strftime("%d.%m.%Y %H:%M")}'
def get_total_cost(self):
"""计算订单总价"""
# 注意:这里需要遍历OrderItem来获取实际的购买价格和数量
# 如果OrderItem的price字段代表的是购买时的单价,则应使用OrderItem的price
# 否则,如果OrderItem只关联Item,且Item的price是实时价格,则使用Item.price
# 假设OrderItem的price和quantity是准确的
return sum(item.get_cost() for item in self.order_items.all()) # 访问related_name 'order_items'
class OrderItem(models.Model):
"""
订单项模型,用于连接订单和商品,并记录购买时的价格和数量。
"""
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='order_items')
item = models.ForeignKey(Item, related_name='order_items', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2) # 购买时的单价
quantity = models.PositiveIntegerField(default=1)
def __str__(self):
return f'{self.id}'
def get_cost(self):
"""计算单个订单项的总价"""
return self.price * self.quantity模型说明:
Stripe Checkout通过创建会话(Session)来引导用户完成支付。我们需要为单品购买和订单购买分别创建视图。
views.py
import stripe
from django.conf import settings
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views import View
from django.views.generic import TemplateView
from .models import Item, Order, OrderItem
# 初始化Stripe API密钥
stripe.api_key = settings.STRIPE_SECRET_KEY
class ProductLandingPageView(TemplateView):
"""
单个商品详情页视图。
"""
template_name = 'landing.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
item_id = self.kwargs["item_id"]
item = get_object_or_404(Item, id=item_id)
context['item'] = item
context.update({
"STRIPE_PUBLIC_KEY": settings.STRIPE_PUBLISHABLE_KEY
})
return context
class CreateCheckoutSessionView(View):
"""
创建单个商品Stripe Checkout会话的视图。
"""
def get(self, request, *args, **kwargs):
item_id = self.kwargs["item_id"]
# 确保域名与Stripe配置的Webhooks一致,生产环境应使用HTTPS
DOMAIN: str = 'http://127.0.0.1:8000'
item = get_object_or_404(Item, id=item_id) # 使用get_object_or_404更健壮
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[
{
'price_data': {
'currency': 'usd',
'unit_amount': item.price, # 确保这里是美分
'product_data': {
'name': item.name,
},
},
'quantity': 1,
},
],
payment_intent_data={
'metadata': {
'item_id': item.id,
},
},
mode='payment',
success_url=DOMAIN + '/success/',
cancel_url=DOMAIN + '/cancel/',
)
return JsonResponse({'id': session.id})
class CreateCheckoutSessionOrderView(View):
"""
创建订单Stripe Checkout会话的视图。
"""
def get(self, request, *args, **kwargs):
order_id = self.kwargs["order_id"]
DOMAIN: str = 'http://127.0.0.1:8000'
order = get_object_or_404(Order, id=order_id) # 使用get_object_or_404更健壮
# 针对订单,Stripe Checkout通常有两种处理方式:
# 1. 将整个订单作为一个“产品”,价格为订单总价。
# 2. 将订单中的每个商品作为单独的line_item。
# 这里采用第一种方式,将订单总价作为单个line_item。
# 优化:确保订单总价计算正确,且Stripe产品名称使用str(order)获取
total_cost_cents = int(order.get_total_cost() * 100) # 将Decimal转换为整数美分
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[
{
'price_data': {
'currency': 'usd',
'unit_amount': total_cost_cents, # 订单总价(美分)
'product_data': {
'name': str(order), # 正确调用__str__方法
},
},
'quantity': 1, # 订单整体数量为1
},
],
payment_intent_data={
'metadata': {
'order_id': order.id,
},
},
mode='payment',
success_url=DOMAIN + '/success/',
cancel_url=DOMAIN + '/cancel/',
)
return JsonResponse({'id': session.id})
class OrderView(TemplateView):
"""
订单详情页视图。
"""
template_name = 'order.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
order_id = self.kwargs["order_id"]
order = get_object_or_404(Order, id=order_id)
context['order'] = order
context.update({
"STRIPE_PUBLIC_KEY": settings.STRIPE_PUBLISHABLE_KEY,
'name': str(order), # 确保这里也正确调用__str__
'items': order.order_items.all(), # 访问OrderItem而不是Item
'total': order.get_total_cost()
})
return context
class SuccessView(TemplateView):
"""
支付成功页面视图。
"""
template_name = "success.html"
class CancelView(TemplateView):
"""
支付取消页面视图。
"""
template_name = "cancel.html"视图说明与优化:
URL配置将HTTP请求映射到相应的Django视图。
项目介绍: eShop是基于eFrameWork低代码开发平台搭建的微信公众号商城系统,主要功能包括:产品、订单、购物车、收藏、收货地址。已集成微信登录、微信支付、分享等接口。更多功能可自行二次开发实现。 当前发布的数据库有两个版本,SQLServer和SQLite(无需安装数据库),默认为SQLite,根据实际需要切换。 项目版本:VS2012+, 数据库版本:S
13
urls.py
from api.views import (
CancelView, SuccessView, CreateCheckoutSessionView,
ProductLandingPageView, OrderView, CreateCheckoutSessionOrderView
)
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
# 订单支付Checkout会话创建,注意添加了尾部斜杠
path('order_checkout/<int:order_id>/', CreateCheckoutSessionOrderView.as_view(), name='order_checkout'),
# 订单详情页
path('order/<int:order_id>/', OrderView.as_view(), name='order'),
# 单个商品详情页
path('item/<int:item_id>/', ProductLandingPageView.as_view(), name='item'),
# 单个商品支付Checkout会话创建
path('buy/<int:item_id>/', CreateCheckoutSessionView.as_view(), name='buy'),
# 支付取消页
path('cancel/', CancelView.as_view(), name='cancel'),
# 支付成功页
path('success/', SuccessView.as_view(), name='success'),
]URL配置说明与404排查:
前端负责触发Stripe Checkout流程。
order.html (示例,landing.html 类似)
{% extends 'base.html' %}
{% block title %}
订单支付
{% endblock %}
{% block content %}
<div class="description">
<h3>{{ name }}</h3>
<div class="order-info">
<h5>总成本 {{ total }} USD.</h5>
</div>
<button id="buy-button" data-order-id="{{ order.id }}">购买</button>
</div>
<script src="https://js.stripe.com/v3/"></script>
<script>
document.getElementById('buy-button').addEventListener('click', function() {
var orderId = this.getAttribute('data-order-id');
var stripe = Stripe("{{ STRIPE_PUBLIC_KEY }}"); // 从Django上下文获取Stripe公钥
// 发送请求到Django后端创建Checkout会话
fetch('/order_checkout/' + orderId + '/') // 确保URL与urls.py中的模式一致,包含尾部斜杠
.then(function(response) {
if (!response.ok) {
// 如果后端返回非2xx状态码,抛出错误
return response.json().then(errorData => {
throw new Error(errorData.message || '后端创建会话失败');
});
}
return response.json();
})
.then(function (session) {
// 重定向到Stripe Checkout页面
return stripe.redirectToCheckout({ sessionId: session.id });
})
.catch(function(error) {
console.error('支付流程出错:', error);
alert('支付过程中发生错误,请稍后再试。'); // 友好提示用户
});
});
</script>
{% endblock %}前端说明:
用户完成Stripe Checkout后,Stripe会将用户重定向到 success_url 或 cancel_url。
在实际生产环境中,支付成功后,您需要通过Stripe Webhooks来异步更新订单状态,而不是仅仅依赖 success_url。因为用户可能在支付成功页面加载前关闭浏览器,或者支付本身是异步完成的。
以上就是Django与Stripe集成:实现单品与订单支付的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号