You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django集成PayPal支付无法接收IPN响应及相关实现问题

Django集成PayPal IPN问题解决指南

核心问题解答

1. IPN无需自行编写视图

你使用的django-paypal库已经封装好了IPN监听、验证的全套逻辑,只需要在项目路由中注册库自带的IPN路由即可:

# 项目主urls.py
urlpatterns = [
    # 你的其他路由
    path('paypal/ipn/', include('paypal.standard.ipn.urls')),
]

注册完成后reverse('paypal-ipn')就能正常解析,你代码中注释的notify_url配置可以直接启用。

2. 表单存放位置说明

你当前把PayPalPaymentsForm放在PaymentProcess视图中的写法完全正确:

  • 这个表单的作用是生成跳转到PayPal支付页的提交入口,不需要额外存放在其他位置
  • 你注释的return_url、cancel_return对应两个自定义视图,需要你自行编写,分别处理用户支付成功后跳转、支付取消后跳转的逻辑,对应路由命名为payment_done、payment_canceled即可

3. 信号生效配置步骤

你写的信号逻辑本身没有问题,只要做两处配置保证Django启动时能加载到信号即可:

  1. 首先在你存放signals.py的应用的apps.py中添加信号导入逻辑:
from django.apps import AppConfig

class 你的应用名Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = '你的应用名'

    def ready(self):
        import 你的应用名.signals
  1. 检查settings.py的INSTALLED_APPS中已经注册了paypal.standard.ipn和你自己的业务应用

修正后可直接使用的代码示例

修正后的PaymentProcess视图

class PaymentProcess(View):
    def get(self,request):
        host = request.get_host()
        payment = PaymentRecords.objects.get(
            order_id = request.session['order_id']
        )
        paypal_dict = {
            'business': settings.PAYPAL_RECEIVER_EMAIL,
            'amount': payment.total_amount,
            'item_name': 'Item_Name_xyz',
            'invoice': f'INV{payment.order_id}{str(randint(10,5000))}', # 用订单号保证唯一
            'currency_code': 'USD',
            'custom': payment.order_id, # 传递订单号,IPN回调时用于关联订单
            'notify_url': 'http://{}{}'.format(host, reverse('paypal-ipn')),
            'return_url': 'http://{}{}'.format(host, reverse('payment_done')),
            'cancel_return': 'http://{}{}'.format(host, reverse('payment_canceled')),
        }
        form = PayPalPaymentsForm(initial=paypal_dict)
        return render(request , 'restprac/index.html',{'form':form})

修正后的signals.py

from paypal.standard.ipn.signals import valid_ipn_received
from paypal.standard.models import ST_PP_COMPLETED
from django.conf import settings
from .models import PaymentRecords

def show_me_the_money(sender, **kwargs):
    ipn_obj = sender
    if ipn_obj.payment_status == ST_PP_COMPLETED:
        # 校验收款邮箱防止篡改
        if ipn_obj.receiver_email != settings.PAYPAL_RECEIVER_EMAIL:
            return
        # 关联业务订单
        try:
            payment = PaymentRecords.objects.get(order_id=ipn_obj.custom)
        except PaymentRecords.DoesNotExist:
            return
        # 校验金额和币种
        if ipn_obj.mc_gross == payment.total_amount and ipn_obj.mc_currency == 'USD':
            # 支付校验通过,修改订单状态、执行业务逻辑
            payment.is_paid = True
            payment.paypal_txn_id = ipn_obj.txn_id
            payment.save()
            # 其他后续逻辑:发通知、解锁服务等

valid_ipn_received.connect(show_me_the_money)

注意事项

  • 本地测试时需要用内网穿透工具把本地端口映射到公网,PayPal才能正常发送IPN回调到本地环境
  • 生产环境的notify_url必须使用HTTPS协议,PayPal强制要求生产回调地址走HTTPS
  • invoice字段必须全局唯一,重复的发票号会导致PayPal拒绝返回回调
  • 不要在return_url对应的视图中做支付状态变更,该地址是用户前端跳转地址,存在伪造风险,所有支付状态变更逻辑必须放在IPN信号中处理

内容的提问来源于stack exchange,提问作者Atif Shafi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:15:02