django 實現(xiàn)電子支付功能的示例代碼
思路:調(diào)用第三方支付 API 接口實現(xiàn)支付功能。本來想用支付寶來實現(xiàn)第三方網(wǎng)站的支付功能的,但是在實際操作中發(fā)現(xiàn)支付寶沒有 Python 接口,網(wǎng)上雖然有他人二次封裝的的 Python 接口,但是對我這個小白白來說上手還是有點難度,后來發(fā)現(xiàn) PayPal 有現(xiàn)成的 Django 模塊,想著以學習的目的來實現(xiàn)這一功能(其實還是自己辣雞),就決定以 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'
執(zhí)行同步數(shù)據(jù)庫操作。
./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 付款操作,建立含有正確數(shù)據(jù)的付款按鈕。
@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 中的常數(shù),所以也要導入 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>產(chǎn)品名稱</td>
<td width=100 align=center>單價</td>
<td width=100 align=center>數(shù)量</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>您剛剛?cè)∠薖ayPal的付款</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 在處理完在線付款流程后會另外發(fā)送一個 HTTP 數(shù)據(jù)給我們的網(wǎng)站,我們應該編寫一個處理這個信號的函數(shù),更改我們數(shù)據(jù)庫中的內(nèi)容,為了確保我們設置的監(jiān)聽函數(shù)可以被系統(tǒng)加載且保持運行,在 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)
在同一文件夾下再創(chuàng)建一個名為 apps.py 的文件,確保上述編寫的函數(shù)在一開始的時候就能夠加載。
from django.apps import AppConfig class PaymentConfig(AppConfig): name = 'mysite' verbose_name = 'Mysite' def ready(self): import mysite.signal
在同一文件夾下的 __init__.py 中加入以下語句,確保我們在應用程序初始化加載的時候,可以把我們自定義的應用程序環(huán)境設置成能夠加載自定義的工作。
default_app_config = 'mysite.apps.PaymentConfig'
通過上述設置,我們的網(wǎng)站已經(jīng)可以正確地接受訂單并使用 PayPal 付款了,我們可以在 PayPal 開發(fā)者網(wǎng)站( https://developer.paypal.com/ )申請一個測試賬號來進行付款測試。
點擊進入 dashboard 界面,點擊 sandbox 下的 account 選項,我們可以在此創(chuàng)建一個測試賬號。

點擊創(chuàng)建賬號下的 profile 選項,進入詳情頁,設置此賬號的密碼,并將 Payment Review 的功能設置為 Off。

接下來我們便可以在我們的網(wǎng)站中使用這個測試賬號付款了,點擊前往付款,調(diào)用 payment 函數(shù),加載含有正確數(shù)據(jù)的付款按鈕,點擊后便跳轉(zhuǎn)到 paypal 的沙盒付款頁面,我們在其中填入我們之前建立好的測試賬號信息,登錄后便可以付款了。

付款成功后便返回我們之前編寫好的付款成功頁面。

注意:中國大陸的 paypal 賬號不能用來測試實際支付,需要大陸以外的 paypal 賬戶才可測試實際支付。(真是坑。。。)
不然付款的時候會出現(xiàn)下列界面。

到這里,我們的付款便已經(jīng)成功了,但是 PayPal 無法將支付狀態(tài)通知發(fā)送到我們的應用,這是由于我們的項目運行在外部無法訪問的 127.0.0.1 上。我們使用 Ngrok 來實現(xiàn)因特網(wǎng)訪問開發(fā)環(huán)境。
在 Ngrok 官網(wǎng) https://ngrok.com/ 下載解壓文件并關聯(lián)賬號后,運行下列命令。
./ngrok http 8000
這個命令將在 8000 端口為本地主機創(chuàng)建一個通道并為其設置一個網(wǎng)絡可以訪問的主機名稱,得到以下輸出:

我們可以通過訪問 Forwarding 中的網(wǎng)址來連接我們構建在本地的網(wǎng)站。
然后付款后便能在自己本地網(wǎng)站的后臺管理看到 paypal ipn 的信息,我這里顯示的狀態(tài)是 pending,按理來說應該是 completed ,可能 paypal 設置中需要更改,這樣的話需要將 signal.py 中 ST_PP_COMPLETED 修改為 ST_PP_PENDING,這樣 signal.py 便能正常處理 paypal 返回的信息,將訂單狀態(tài)更改為已完成。

至此,我們便完成了調(diào)用 paypal 實現(xiàn)第三方網(wǎng)站支付的功能。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
flask中響應錯誤的處理及errorhandler的應用方式
這篇文章主要介紹了flask中響應錯誤的處理及errorhandler的應用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
Django生成數(shù)據(jù)庫及添加用戶報錯解決方案
這篇文章主要介紹了Django生成數(shù)據(jù)庫及添加用戶報錯解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10

