当前位置:主页 > python教程 > django实现电子支付功能的示例代码

django实现电子支付功能实例讲解

发布:2019-06-09 14:14:54 148


给网友朋友们带来一篇django相关的编程文章,网友欧恺歌根据主题投稿了本篇教程内容,涉及到django、电子支付、django实现电子支付功能的示例代码相关内容,已被887网友关注,内容中涉及的知识点可以在下方直接下载获取。

django实现电子支付功能的示例代码

思路:调用第三方支付 API 接口实现支付功能。本来想用支付宝来实现第三方网站的支付功能的,但是在实际操作中发现支付宝没有 Python 接口,网上虽然有他人二次封装的的 Python 接口,但是对我这个小白白来说上手还是有点难度,后来发现 PayPal 有现成的 Django 模块,想着以学习的目的来实现这一功能(其实还是自己辣鸡),就决定以 PayPal 的电子支付功能来练手。

首先,安装 PayPal 的 Django 模块:django-paypal,具体介绍可以参考 GitHub上说明: https://github.com/spookylukey/django-paypal

pip install django-paypal

然后在 settings.py 中的 INSTALLED_APPS 将 'paypal.standard.ipn' 加入。并在 settings.py 中添加下列语句。

# 此付款机制作为测试用
PAYPAL_TEST = True
# 设置收款的 PayPal 电子邮件账户
PAYPAL_REVEIVER_EMAIL = 'your email'

执行同步数据库操作。

./manage.py migrate

urls.py 中加入下列样式。分别为付款完成通知,处理账务,显示完成付款,取消付款操作。

url(r'^paypal/', include('paypal.standard.ipn.urls')), # 付款完成通知
url(r'^payment/(\d+)/$', views.payment),
url(r'^done/$', views.payment_done),
url(r'^canceled/$', views.payment_canceled),

PayPal 付款操作,建立含有正确数据的付款按钮。

@login_required
def payment(request, order_id):
 all_categories = models.Category.objects.all()
 try:
  order = models.Order.objects.get(id=order_id)
 except:
  messages.add_message(request, messages.WARNING, "订单编号错误,无法处理付款。")
  return redirect('/myorders/')
 all_order_items = models.OrderItem.objects.filter(order=order)
 items = list()
 total = 0
 for order_item in all_order_items:
  t = dict()
  t['name'] = order_item.product.name
  t['price'] = order_item.product.price
  t['quantity'] = order_item.quantity
  t['subtotal'] = order_item.product.price * order_item.quantity
  total = total + order_item.product.price
  items.append(t)

 host = request.get_host()
 paypal_dict = {
  "business": settings.PAYPAL_REVEIVER_EMAIL,
  "amount": total,
  "item_name": "迷你小电商商品编号:{}".format(order_id),
  "invoice": "invoice-{}".format(order_id),
  "currency_code": 'CNY',
  "notify_url": "http://{}{}".format(host, reverse('paypal-ipn')),
  "return_url": "http://{}/done/".format(host),
  "cancel_return": "http://{}/canceled/".format(host),
  }
 paypal_form = PayPalPaymentsForm(initial=paypal_dict)
 template = get_template('payment.html')
 html = template.render(context=locals(), request=request)
 return HttpResponse(html)

由于用到了 django-paypal 提供的 PayPalPaymentForm 类。因此在 views.py 的前面也要导入这个类。另外,因为用到了 settings.py 中的常数,所以也要导入 settings,语句如下:

from django.conf import settings
from paypal.standard.forms import PayPalPaymentsForm
from django.core.urlresolvers import reverse

付款完成。

@csrf_exempt #csrf 验证
def payment_done(request):
 template = get_template('payment_done.html')
 html = template.render(context=locals(), request=request)
 return HttpResponse(html)

取消付款。

@csrf_exempt
def payment_canceled(request):
 template = get_template('payment_canceled.html')
 html = template.render(context=locals(), request=request)
 return HttpResponse(html)

PayPal 付款页面。

<!-- payment.html (mshop project) -->
{% extends "base.html" %}
{% block title %}选择您的付款方式{% endblock %}
{% block content %}
<div class='container'>
{% for message in messages %}
 <div class='alert alert-{{message.tags}}'>{{ message }}</div>
{% endfor %}
 <div class='row'>
  <div class='col-md-12'>
   <div class='panel panel-default'>
    <div class='panel-heading' align=center>
     <h3>欢迎光临迷你小电商</h3>
      {% if user.socialaccount_set.all.0.extra_data.name %}
       {{user.socialaccount_set.all.0.extra_data.name}}<br/>
       <img src='{{user.socialaccount_set.all.0.get_avatar_url}}' width='100'>
      {% else %}
       Welcome: {{ user.username }}
      {% endif %}
    </div>
   </div>
  </div>
 </div>
 <div class='row'>
  <div class='col-sm-12'>
   <div class='panel panel-info'>
    <div class='panel panel-heading'>
     <h4>在线付款(订单编号:{{order.id}})</h4>
    </div>
    <div class='panel panel-body'>
     {% for item in items %}
     {% if forloop.first %}
     <table border=1>
      <tr>
       <td width=300 align=center>产品名称</td>
       <td width=100 align=center>单价</td>
       <td width=100 align=center>数量</td>
       <td width=100 align=center>小计</td>
      </tr>
     {% endif %}
      <div class='listgroup'>
       <div class='listgroup-item'>
        <tr>
         <td>{{ item.name }}</td>
         <td align=right>{{ item.price }}</td>
         <td align=center>{{ item.quantity }}</td>
         <td align=right>{{ item.subtotal }}</td>
        </tr>
       </div>
      </div>
     {% if forloop.last %}
     </table>
     {% endif %}
     {% empty %}
      <em>此订单是空的</em>
     {% endfor %}
     
     {{ paypal_form.render }}
    </div>
    <div class='panel panel-footer'>
     NT$:{{ total }}元
    </div>
   </div>
  </div>
 </div>
</div>
{% endblock %}

付款完成页面。

<!-- payment_done.html (mshop project) -->
{% extends "base.html" %}
{% block title %}Pay using PayPal{% endblock %}
{% block content %}
<div class='container'>
{% for message in messages %}
 <div class='alert alert-{{message.tags}}'>{{ message }}</div>
{% endfor %}
 <div class='row'>
  <div class='col-md-12'>
   <div class='panel panel-default'>
    <div class='panel-heading' align=center>
     <h3>欢迎光临迷你小电商</h3>
      {% if user.socialaccount_set.all.0.extra_data.name %}
       {{user.socialaccount_set.all.0.extra_data.name}}<br/>
       <img src='{{user.socialaccount_set.all.0.get_avatar_url}}' width='100'>
      {% else %}
       Welcome: {{ user.username }}
      {% endif %}
    </div>
   </div>
  </div>
 </div>
 <div class='row'>
  <div class='col-sm-12'>
   <div class='panel panel-info'>
    <div class='panel panel-heading'>
     <h4>从PayPal付款成功</h4>
    </div>
    <div class='panel panel-body'>
     感谢您的支持,我们会尽快处理您的订单。
    </div>
    <div class='panel panel-footer'>
    </div>
   </div>
  </div>
 </div>
</div>
{% endblock %}

取消付款页面。

<!-- payment_canceled.html (mshop project) -->
{% extends "base.html" %}
{% block title %}PayPal 付款取消通知{% endblock %}
{% block content %}
<div class='container'>
{% for message in messages %}
 <div class='alert alert-{{message.tags}}'>{{ message }}</div>
{% endfor %}
 <div class='row'>
  <div class='col-md-12'>
   <div class='panel panel-default'>
    <div class='panel-heading' align=center>
     <h3>欢迎光临迷你小电商</h3>
      {% if user.socialaccount_set.all.0.extra_data.name %}
       {{user.socialaccount_set.all.0.extra_data.name}}<br/>
       <img src='{{user.socialaccount_set.all.0.get_avatar_url}}' width='100'>
      {% else %}
       Welcome: {{ user.username }}
      {% endif %}
    </div>
   </div>
  </div>
 </div>
 <div class='row'>
  <div class='col-sm-12'>
   <div class='panel panel-info'>
    <div class='panel panel-heading'>
     <h4>您刚刚取消了PayPal的付款</h4>
    </div>
    <div class='panel panel-body'>
     <p>请再次检查您的付款,或是返回<a href='/myorders/'>我的订单</a>选用其它付款方式。</p>
    </div>
    <div class='panel panel-footer'>
    </div>
   </div>
  </div>
 </div>
</div>
{% endblock %}

PayPal 在处理完在线付款流程后会另外发送一个 HTTP 数据给我们的网站,我们应该编写一个处理这个信号的函数,更改我们数据库中的内容,为了确保我们设置的监听函数可以被系统加载且保持运行,在 views.py 的同级目录中建立一个名为 signal.py 文件。

from mysite import models
from paypal.standard.models import ST_PP_COMPLETED
from paypal.standard.ipn.signals import valid_ipn_received

def payment_notfication(sender, **kwargs):
 ipn_obj = sender
 if ipn_obj.payment_status == ST_PP_COMPLETED:
  order_id = ipn_obj.invocie.split('-')[-1]
  order = models.Order.objects.get(id = order_id)
  order_id.paid = True
  order.save()

valid_ipn_received.connect(payment_notfication)

在同一文件夹下再创建一个名为 apps.py 的文件,确保上述编写的函数在一开始的时候就能够加载。

from django.apps import AppConfig

class PaymentConfig(AppConfig):
 name = 'mysite'
 verbose_name = 'Mysite'

 def ready(self):
  import mysite.signal

在同一文件夹下的 __init__.py 中加入以下语句,确保我们在应用程序初始化加载的时候,可以把我们自定义的应用程序环境设置成能够加载自定义的工作。

default_app_config = 'mysite.apps.PaymentConfig'

通过上述设置,我们的网站已经可以正确地接受订单并使用 PayPal 付款了,我们可以在 PayPal 开发者网站( https://developer.paypal.com/ )申请一个测试账号来进行付款测试。

点击进入 dashboard 界面,点击 sandbox 下的 account 选项,我们可以在此创建一个测试账号。

django 实现电子支付功能的示例代码

点击创建账号下的 profile 选项,进入详情页,设置此账号的密码,并将 Payment Review 的功能设置为 Off。

django 实现电子支付功能的示例代码

接下来我们便可以在我们的网站中使用这个测试账号付款了,点击前往付款,调用 payment 函数,加载含有正确数据的付款按钮,点击后便跳转到 paypal 的沙盒付款页面,我们在其中填入我们之前建立好的测试账号信息,登录后便可以付款了。

django 实现电子支付功能的示例代码

付款成功后便返回我们之前编写好的付款成功页面。

django 实现电子支付功能的示例代码

注意:中国大陆的 paypal 账号不能用来测试实际支付,需要大陆以外的 paypal 账户才可测试实际支付。(真是坑。。。)

不然付款的时候会出现下列界面。

django 实现电子支付功能的示例代码

到这里,我们的付款便已经成功了,但是 PayPal 无法将支付状态通知发送到我们的应用,这是由于我们的项目运行在外部无法访问的 127.0.0.1 上。我们使用 Ngrok 来实现因特网访问开发环境。

在 Ngrok 官网  https://ngrok.com/ 下载解压文件并关联账号后,运行下列命令。

./ngrok http 8000

这个命令将在 8000 端口为本地主机创建一个通道并为其设置一个网络可以访问的主机名称,得到以下输出:

django 实现电子支付功能的示例代码

我们可以通过访问 Forwarding 中的网址来连接我们构建在本地的网站。

然后付款后便能在自己本地网站的后台管理看到 paypal ipn 的信息,我这里显示的状态是 pending,按理来说应该是 completed ,可能 paypal 设置中需要更改,这样的话需要将 signal.py 中 ST_PP_COMPLETED 修改为 ST_PP_PENDING,这样 signal.py 便能正常处理 paypal 返回的信息,将订单状态更改为已完成。

django 实现电子支付功能的示例代码

至此,我们便完成了调用 paypal 实现第三方网站支付的功能。


参考资料

相关文章

  • django配置阿里云OSS存储media文件的例子

    发布:2021-04-24

    今天小编就为大家分享一篇django 配置阿里云OSS存储media文件的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧


  • django使用admin站点上传图片的代码分享

    发布:2020-03-30

    今天小编就为大家分享一篇django使用admin站点上传图片的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧


  • Django的HttpRequest和HttpResponse对象详解

    发布:2022-12-06

    给大家整理一篇关于Django的教程,这篇文章主要介绍了Django的HttpRequest和HttpResponse对象,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下


  • Django中修改js css文件但浏览器无法及时与之改变的解决方法

    发布:2019-09-15

    今天小编就为大家分享一篇解决Django中修改js css文件但浏览器无法及时与之改变的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧


  • django-allauth基础知识点及用法

    发布:2020-02-07

    这篇文章主要介绍了django-allauth入门学习和使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧


  • django框架使用mysql的教程介绍(代码示例)

    django框架使用mysql的教程介绍(代码示例)

    发布:2022-10-18

    给大家整理了关于django的教程,​本篇文章给大家带来的内容是关于django框架使用mysql的教程介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。


  • Django前后台数据传递的实例方法

    发布:2019-12-13

    本篇文章主要介绍了Django 前后台的数据传递的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧


  • django框架CSRF防护原理及实例用法

    发布:2021-05-10

    这篇文章主要介绍了django框架CSRF防护原理与用法,结合实例形式分析了Django框架CSRF防护的概念、原理、使用方法及相关操作注意事项,需要的朋友可以参考下


网友讨论