Django后端使用Stripe实现含多参会人信息的活动预订支付关联问题
Django+Stripe活动预订支付关联方案
核心结论
不需要将所有参会人信息传入Stripe请求,完全可以沿用标准场景下「预创建本地订单+传递唯一标识回调关联」的逻辑,适配复杂参会人场景即可。
具体实现步骤
- 第一步:本地预存预订与参会人全量数据
用户提交所有参会人信息后,先在本地数据库创建预订主记录,状态设为待支付,同时将所有参会人信息关联到该预订记录存入数据库,生成唯一的预订编号。参考Django模型定义如下:
from django.db import models from django.utils.translation import gettext_lazy as _ class EventBooking(models.Model): class BookingStatus(models.TextChoices): PENDING = "pending", _("待支付") PAID = "paid", _("已支付") CANCELLED = "cancelled", _("已取消") booking_no = models.CharField(max_length=32, unique=True, verbose_name="预订编号") total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="总金额") status = models.CharField(max_length=16, choices=BookingStatus.choices, default=BookingStatus.PENDING, verbose_name="预订状态") created_at = models.DateTimeField(auto_now_add=True) # 可补充其他业务字段:活动ID、下单用户ID等 class EventAttendee(models.Model): booking = models.ForeignKey(EventBooking, on_delete=models.CASCADE, related_name="attendees", verbose_name="所属预订") name = models.CharField(max_length=64, verbose_name="参会人姓名") phone = models.CharField(max_length=16, verbose_name="手机号") # 可补充其他参会人专属字段:身份证号、特殊需求等
- 第二步:创建Stripe支付会话时仅传递唯一预订标识
创建Stripe支付会话时,仅需将本地生成的唯一预订编号存入Stripe的metadata字段即可,不需要传递任何参会人相关信息。参考代码如下:
import stripe from django.conf import settings stripe.api_key = settings.STRIPE_SECRET_KEY def create_stripe_checkout_session(booking): session = stripe.checkout.Session.create( payment_method_types=['card'], line_items=[{ 'price_data': { 'currency': 'cny', 'product_data': { 'name': f'活动预订 {booking.booking_no}', }, 'unit_amount': int(booking.total_amount * 100), }, 'quantity': 1, }], mode='payment', success_url=settings.STRIPE_SUCCESS_URL, cancel_url=settings.STRIPE_CANCEL_URL, # 仅传递本地唯一预订编号,无需传入参会人信息 metadata={ 'booking_no': booking.booking_no, } ) return session
- 第三步:Webhook回调时关联本地数据完成订单履约
接收Stripe支付成功的Webhook回调时,从返回的session数据的metadata中取出预订编号,查询本地数据库即可直接获取对应的预订记录和全量参会人信息,更新预订状态为已支付后即可完成后续履约逻辑。参考代码如下:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt import stripe @csrf_exempt def stripe_webhook(request): payload = request.body sig_header = request.META['HTTP_STRIPE_SIGNATURE'] event = None try: event = stripe.Webhook.construct_event( payload, sig_header, settings.STRIPE_WEBHOOK_SECRET ) except ValueError: return HttpResponse(status=400) except stripe.error.SignatureVerificationError: return HttpResponse(status=400) # 处理支付成功事件 if event['type'] == 'checkout.session.completed': session = event['data']['object'] # 从metadata获取本地预订编号 booking_no = session.get('metadata', {}).get('booking_no') if not booking_no: return HttpResponse(status=400) try: booking = EventBooking.objects.get(booking_no=booking_no, status=EventBooking.BookingStatus.PENDING) except EventBooking.DoesNotExist: return HttpResponse(status=404) # 更新预订状态 booking.status = EventBooking.BookingStatus.PAID booking.save() # 直接通过 booking.attendees.all() 即可获取全量参会人信息,执行后续履约逻辑 # 如发送参会通知、生成核销凭证等 return HttpResponse(status=200)
方案优势
- 所有业务敏感数据(参会人个人信息等)均存储在本地,避免跨境数据传输的合规风险,也不会受Stripe接口字段限制
- 逻辑与标准商品支付流程对齐,开发成本低,问题排查路径清晰
- 待支付状态的预订数据已完整存储,用户支付失败后再次发起支付无需重复填写参会人信息,用户体验更好
内容的提问来源于stack exchange,提问作者bodger
相关产品推荐
相关产品推荐

