django 實(shí)現(xiàn)電子支付功能的示例代碼
思路:調(diào)用第三方支付 API 接口實(shí)現(xiàn)支付功能。本來想用支付寶來實(shí)現(xiàn)第三方網(wǎng)站的支付功能的,但是在實(shí)際操作中發(fā)現(xiàn)支付寶沒有 Python 接口,網(wǎng)上雖然有他人二次封裝的的 Python 接口,但是對我這個小白白來說上手還是有點(diǎn)難度,后來發(fā)現(xiàn) PayPal 有現(xiàn)成的 Django 模塊,想著以學(xué)習(xí)的目的來實(shí)現(xiàn)這一功能(其實(shí)還是自己辣雞),就決定以 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 中添加下列語句。
# 此付款機(jī)制作為測試用 PAYPAL_TEST = True # 設(shè)置收款的 PayPal 電子郵件賬戶 PAYPAL_REVEIVER_EMAIL = 'your email'
執(zhí)行同步數(shù)據(jù)庫操作。
./manage.py migrate
urls.py 中加入下列樣式。分別為付款完成通知,處理賬務(wù),顯示完成付款,取消付款操作。
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 的前面也要導(dǎo)入這個類。另外,因?yàn)橛玫搅?settings.py 中的常數(shù),所以也要導(dǎo)入 settings,語句如下:
from django.conf import settings from paypal.standard.forms import PayPalPaymentsForm from django.core.urlresolvers import reverse
付款完成。
@csrf_exempt #csrf 驗(yàn)證 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)站,我們應(yīng)該編寫一個處理這個信號的函數(shù),更改我們數(shù)據(jù)庫中的內(nèi)容,為了確保我們設(shè)置的監(jiān)聽函數(shù)可以被系統(tǒng)加載且保持運(yùn)行,在 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 中加入以下語句,確保我們在應(yīng)用程序初始化加載的時候,可以把我們自定義的應(yīng)用程序環(huán)境設(shè)置成能夠加載自定義的工作。
default_app_config = 'mysite.apps.PaymentConfig'
通過上述設(shè)置,我們的網(wǎng)站已經(jīng)可以正確地接受訂單并使用 PayPal 付款了,我們可以在 PayPal 開發(fā)者網(wǎng)站( https://developer.paypal.com/ )申請一個測試賬號來進(jìn)行付款測試。
點(diǎn)擊進(jìn)入 dashboard 界面,點(diǎn)擊 sandbox 下的 account 選項,我們可以在此創(chuàng)建一個測試賬號。
點(diǎn)擊創(chuàng)建賬號下的 profile 選項,進(jìn)入詳情頁,設(shè)置此賬號的密碼,并將 Payment Review 的功能設(shè)置為 Off。
接下來我們便可以在我們的網(wǎng)站中使用這個測試賬號付款了,點(diǎn)擊前往付款,調(diào)用 payment 函數(shù),加載含有正確數(shù)據(jù)的付款按鈕,點(diǎn)擊后便跳轉(zhuǎn)到 paypal 的沙盒付款頁面,我們在其中填入我們之前建立好的測試賬號信息,登錄后便可以付款了。
付款成功后便返回我們之前編寫好的付款成功頁面。
注意:中國大陸的 paypal 賬號不能用來測試實(shí)際支付,需要大陸以外的 paypal 賬戶才可測試實(shí)際支付。(真是坑。。。)
不然付款的時候會出現(xiàn)下列界面。
到這里,我們的付款便已經(jīng)成功了,但是 PayPal 無法將支付狀態(tài)通知發(fā)送到我們的應(yīng)用,這是由于我們的項目運(yùn)行在外部無法訪問的 127.0.0.1 上。我們使用 Ngrok 來實(shí)現(xiàn)因特網(wǎng)訪問開發(fā)環(huán)境。
在 Ngrok 官網(wǎng) https://ngrok.com/ 下載解壓文件并關(guān)聯(lián)賬號后,運(yùn)行下列命令。
./ngrok http 8000
這個命令將在 8000 端口為本地主機(jī)創(chuàng)建一個通道并為其設(shè)置一個網(wǎng)絡(luò)可以訪問的主機(jī)名稱,得到以下輸出:
我們可以通過訪問 Forwarding 中的網(wǎng)址來連接我們構(gòu)建在本地的網(wǎng)站。
然后付款后便能在自己本地網(wǎng)站的后臺管理看到 paypal ipn 的信息,我這里顯示的狀態(tài)是 pending,按理來說應(yīng)該是 completed ,可能 paypal 設(shè)置中需要更改,這樣的話需要將 signal.py 中 ST_PP_COMPLETED 修改為 ST_PP_PENDING,這樣 signal.py 便能正常處理 paypal 返回的信息,將訂單狀態(tài)更改為已完成。
至此,我們便完成了調(diào)用 paypal 實(shí)現(xiàn)第三方網(wǎng)站支付的功能。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ipython jupyter notebook中顯示圖像和數(shù)學(xué)公式實(shí)例
這篇文章主要介紹了ipython jupyter notebook中顯示圖像和數(shù)學(xué)公式實(shí)例,具有很好的參考價值,希望對有所幫助。一起跟隨小編過來看看吧2020-04-04使用Python實(shí)現(xiàn)FTP文件自動傳輸腳本
這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)FTP文件自動傳輸腳本,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以了解下2023-12-12python中json、字典的區(qū)別以及相互轉(zhuǎn)換方法
在Python中我們經(jīng)常會用到JSON格式的數(shù)據(jù),而將JSON格式轉(zhuǎn)化為Python的字典類型是一種常見的操作,這篇文章主要給大家介紹了關(guān)于python中json、字典的區(qū)別以及相互轉(zhuǎn)換方法的相關(guān)資料,需要的朋友可以參考下2023-11-11Numpy創(chuàng)建數(shù)組和隨機(jī)數(shù)組的方法小結(jié)
這篇文章主要為大家詳細(xì)介紹了Numpy創(chuàng)建數(shù)組和隨機(jī)數(shù)組的方法小結(jié),文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Python有一定幫助,具有一定的參考價值,需要的可以參考一下2023-11-11