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;于日前推出了一款曲率达到…

树的遍历-Preorde Traversal,Inorder Traversal,Postoder Traversal

上代码(创建树,先序,中序,后序) #include<bits/stdc.h> using namespace std; typedef struct TreeNode *BinTree; struct TreeNode {BinTree left,right;int value; }; BinTree CreateTree() {BinTree T;int value;cin>>value;if(value0) //如果输入0,则创…

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

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

Page object设计模式

网上看了很多文章&#xff0c;充斥了大量代码。理解起来不容易&#xff0c;在此就我的理解谈谈PageObject设计模式到底是什么东西。 所谓的Page object模式&#xff0c;主要是编写不同层级的脚本&#xff0c;然后一层一层的继承来完成对web测试过程进行分解。 首先&#xff1a;…

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

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

洛谷-图的遍历-P2661-信息传递

#include <iostream> #include <cstdio> using namespace std; const int N 200010; int n, fa[N], ans 0x3f3f3f3f; int get (int x, int &cnt) { //cnt记录环的长度 cnt ;if (fa[x] x) return x;else return get(fa[x], cnt); } int main () {scanf("…

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;必须要理解…

jquery每次动态加载dom,绑定事件会多一次,

jquery绑定事件,每次动态加载dom,绑定的事件会加1,比如动态加载dom5次,点那个点击事件会弹出5次 解决办法就是在每次绑定之前解绑定. $(.seek-footer .btn1).off(click); // 先解绑 $(.seek-footer .btn1).on(click,function () {}) 再绑定 转载于:https://www.cnblogs.com/ybi…

洛谷P3119

省选难度啊啊啊 经评论区的朋友提醒&#xff0c;代码已订正 先说一下该题思路: 首先,这题并非是求最短路,而是求最长路(最长路常用算法一般是拓扑排序,而我这个蒟蒻还没有学会QAQ) 但是这一题既然标签是连通图,那么肯定要用tarjan,考虑到缩点之后每个缩点都具有一定数量的点数,…

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;…

python汉字长度_行中字符串的长度(Python)

我正在尝试将一个.txt文件导入到一些专有软件中&#xff0c;但似乎不断收到一个错误。txt文件的大小几乎是2GB&#xff0c;大约有5600万行。 与制造商交谈后&#xff0c;他们说其中一条线路可能有错误。每一行应该包含一个MD5哈希值&#xff08;32个字符&#xff09;&#xff0…

pilz pnoz s4说明书_如何使用Pilz的安全继电器PNOZ S4?

前面的文章我们曾介绍过皮尔磁(Pilz)的安全继电器PNOZ X3和X2.7P/2.8P &#xff0c;(参考&#xff1a;如何使用Pilz的安全继电器PNOZ X2.7P/X2.8P&#xff1f;)今天这篇文章&#xff0c;我们来介绍另外一款安全继电器产品PNOZ s4.PNOZ s4可以用于急停按钮、安全门、安全开关等场…

推荐系统——协同过滤

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

apriori算法代码_sklearn(九)apriori 关联规则算法,以及FP-growth 算法

是什么&#xff1a;apriori算法是第一个关联规则挖掘算法&#xff0c;利用逐层搜索的迭代方法找出数据库中的项集&#xff08;项的集合&#xff09;的关系&#xff0c;以形成规则&#xff0c;其过程由连接&#xff08;类矩阵运算&#xff09;与剪枝&#xff08;去掉没必要的中间…

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

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

推荐系统——矩阵分解FM

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