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 = 0for order_item in all_order_items:t = dict()t['name'] = order_item.product.namet['price'] = order_item.product.pricet['quantity'] = order_item.quantityt['subtotal'] = order_item.product.price * order_item.quantitytotal = total + order_item.product.priceitems.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_receiveddef payment_notfication(sender, **kwargs):ipn_obj = senderif 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 = Trueorder.save()valid_ipn_received.connect(payment_notfication)

 

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

from django.apps import AppConfigclass 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 选项,我们可以在此创建一个测试账号。

 

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

 

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

 

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

 

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

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

 

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

 

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

./ngrok http 8000

 

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

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

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

 

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

 

转载于:https://www.cnblogs.com/weixuqin/p/9358870.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/427350.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android中怎么保存checkbox中的checked属性_第二十四天HTML中的form表单

form表单用于收集用户信息&#xff0c;如&#xff1a;登录、注册等场景&#xff1b;所有要提交的数据都必须放在form标签中action&#xff1a;提交地址、动作&#xff0c;与input标签中typy标签的submit属性相关联。 &#xff0c;提交地址是action的地址method:提交方法&#x…

Python中曲率与弯曲的转换_1000R曲率更具沉浸感!三星T55曲面显示器评测

在曲面屏的设计上&#xff0c;三星一直在突破极限&#xff0c;比如在2017年推出的49英寸超宽带鱼屏C49HG90&#xff0c;引来众人围观&#xff0c;非常震撼。而在曲率方面&#xff0c;我们常见的有1800R和1500R&#xff0c;但是三星并不满足&#xff0c;于日前推出了一款曲率达到…

opencv resize_opencv-python库基础操作(一)

点赞再看&#xff0c;养成习惯&#xff01;点赞再看&#xff0c;养成习惯&#xff01;点赞再看&#xff0c;养成习惯&#xff01;opencv-python库基础操作0.安装opencv-pythonpip install opencv-python进行下载并安装不过在python中导入opencv库的时候需要"import cv2&qu…

百旺智能编码_【百旺】票字版开票软件操作指南已为您备好,请查阅!

为确保小规模纳税人继续享受税收优惠政策&#xff0c;请广大用户及时对开票软件进行升级~按照国家税务总局要求&#xff0c;从增值税发票税控开票软件五月补丁开始&#xff0c;将停止对增值税发票税控开票软件(税控盘版)“税”字版(以下简称“税”字版)的软件升级更新服务&…

mysql binlog 备份_做好mysql运维,必须熟练掌握备份和恢复,实战一次不行多来几次...

原文&#xff1a;https://www.toutiao.com/i6855460778359816715/平台&#xff1a;头条作者&#xff1a;程序员不就是0和1一、 备份恢复策略进行备份或恢复操作时需要考虑一些因素&#xff1a;1、确定要备份的表的存储引擎是事务型还是非事务型&#xff0c;两种不同的存储引擎备…

在过程中要正式批准可交付成果_干货!软考高项项目管理知识体系5大过程组47个过程...

现在应该很多小伙伴都在紧张的复习软考中&#xff0c;为了让大家更加高效的复习&#xff0c;今天给大家分享软考高级信息系统项目管理师的考试重点&#xff0c;项目管理知识体系的5大过程组47个过程。考高项的朋友都知道&#xff0c;47个过程是非常重要的&#xff0c;必须要理解…

android 组件化_Android 组件化路由框架设计(仿Arouter)

前言在组件化开发中一个必须要面对的问题就是组件间页面跳转&#xff0c;实现的方法有很多&#xff0c;简单的可以通过反射获取&#xff0c;但是比较耗费性能&#xff0c;也可以通过隐式跳转&#xff0c;但是随着页面的增多&#xff0c;过滤条件会随之增多&#xff0c;后期维护…

1668智能下数教程视频_你需要的教程合集更新

最近又收集了一波网络安全资源&#xff0c;在文章最底部。花了将近一天时间整理&#xff0c;只求各位小哥哥能点个在看&#xff0c;分享给身边的朋友。网络安全 --职业发展(渗透的最底部)2019网络安全初识与职业发展https://pan.baidu.com/s/1CAzO8IWxzBj-bOZlJ2eFVg 提取码&am…

关于java中nextline读取空白行的问题

最近在做java作业, 发现了一个问题, 就是nextline其实会接收缓冲区的\r, 使得在程序运行时nextline像是跳过了一样, 其实不然, 它只是读取了上一个enter时的\r, 如我的如下功能代码 public void run() {Scanner scan new Scanner(System.in);int ord, book_order;int flag 0;…

推荐系统——协同过滤

协同过滤 协同过滤算法一般是通过用户之前的喜好或者相似的用户的喜好来推荐商品 基于领域的协同过滤算法一般有两种算法&#xff1a; 基于用户的协同过滤算法(UserCF):基于与用户相似用户的喜好进行推荐基于物品的协同过滤算法(ItemCF):基于用户喜好的物品寻找相似的物品进…

电感检测_几种常用的电流检测方式

RT1720 是一款最高输入电压可达 80V、输出电压可达 60V 的热插拔控制器&#xff0c;它的作用是防止系统受到过高电压和负电压的攻击&#xff0c;同时还能防范过电流可能导致的问题&#xff0c;它的一种应用电路大致如下图所示&#xff1a;为了检测负载电流的大小&#xff0c;RS…

推荐系统——矩阵分解FM

矩阵分解 隐语义模型与矩阵分解 之所以我们提出隐语义模型与矩阵分解&#xff0c;原因就是[[协同过滤]]存在泛化能力弱的问题 而对于隐语义模型而言&#xff0c;我们可以利用隐向量来代表隐藏信息 此外&#xff0c;也可以在一定程度上弥补[[协同过滤]]处理稀疏矩阵能力不足的…

千位分隔符的完整攻略

千位分隔符[1]是很常见的需求&#xff0c;但是输入文本千变万化&#xff0c;如何才能准确添加千分符呢&#xff1f; 纯整数情况 纯整数大概是所有情况里最简单的一种&#xff0c;我们只要正确匹配出千分位就好了。 观察上面的数字&#xff0c;我们可以得出千分位的特征是到字符…

限制按钮点击_Android | 使用 AspectJ 限制按钮快速点击

前言在Android开发中&#xff0c;限制按钮快速点击&#xff08;按钮防抖&#xff09;是一个常见的需求&#xff1b;在这篇文章里&#xff0c;我将介绍一种使用AspectJ的方法&#xff0c;基于注解处理器 & 运行时注解反射的原理。如果能帮上忙&#xff0c;请务必点赞加关注&…

svn不知道这样的主机 怎么解决_家里装修不知道怎么配置净水器,这几招教你轻松解决...

为了保障家庭饮水健康&#xff0c;很多业主都会选择在家中安装一台厨下净水器。但是&#xff0c;如若仅靠它来满足全家人日常洗漱&#xff0c;沐浴和饮用&#xff0c;这势必会极大地影响到全家人的生活品质。这个时候&#xff0c;实阳机电良心建议&#xff0c;全屋净水系统&…

redis系列:通过文章点赞排名案例学习sortedset命令

前言 这一篇文章将讲述Redis中的sortedset类型命令&#xff0c;同样也是通过demo来讲述&#xff0c;其他部分这里就不在赘述了。 项目Github地址&#xff1a;https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-sortedset 案例 demo功能是文章点赞排名等等&am…

xml生成2维码_MyBatis(2)之MyBatis-Generator最佳实践

自定义注释自定义注解指定xml文件模式上一篇文章详细阐述了xml配置文件的各种标签及其含义。其实从标签开始&#xff0c;每一个标签都对应一个实体类。context.class对应标签&#xff0c;而每一个子标签都对应一个属性&#xff1b;如图&#xff1a;标签与实体类的对应关系。有了…

nginx 配置详解_Nginx 配置详解

序言Nginx是lgor Sysoev为俄罗斯访问量第二的http://rambler.ru站点设计开发的。从2004年发布至今&#xff0c;凭借开源的力量&#xff0c;已经接近成熟与完善。Nginx功能丰富&#xff0c;可作为HTTP服务器&#xff0c;也可作为反向代理服务器&#xff0c;邮件服务器。支持Fast…

推荐系统——GBDT+LR

[[逻辑回归模型]] 逻辑回归是在[[线性回归]]的基础上添加了一个Sigmoid函数&#xff08;非线形&#xff09;映射&#xff0c;从而可以使逻辑回归成为一个优秀的分类算法 逻辑回归假设数据服从[[伯努利分布]]&#xff0c;通过[[极大化似然函数]]的方法&#xff0c;运用[[梯度下降…

从燃尽图看项目管理:你的项目哪里出错了?(燃尽图类型全解析)

什么是燃尽图 燃尽图&#xff08;burn down chart&#xff09;是在项目完成之前&#xff0c;对需要完成的工作任务的一种可视化表示。理想情况下&#xff0c;该图表是一个向下的曲线&#xff0c;随着项目任务的逐渐完成“烧尽”至零。 燃尽图常常用于敏捷开发中&#xff0c;作为…