Build an Alipay Payment System with Django: Step‑by‑Step Guide
This tutorial walks you through creating a Django project, configuring RSA keys, setting up Alipay sandbox credentials, writing a Python Alipay class, building front‑end pages, and wiring view functions and URLs to enable PC‑side Alipay payments.
1. Introduction
The article shows how to use the Python web framework Django to implement Alipay payment, a useful project for the upcoming Chinese New Year when many users prefer WeChat or Alipay for transactions.
2. Create Django Project and App
First create a Django project and an app inside it.
3. Configure and Start
Set up urls.py for the project and the app, then run migrations and start the development server.
After configuring the URLs, run python manage.py migrate and python manage.py runserver to verify the app starts correctly.
4. Generate RSA Keys and Configure Alipay
Log in to the Alipay developer console, create an application, and set the encryption method to RSA2 (SHA256). Download the Alipay key generator (or use OpenSSL) to generate a public/private key pair, then upload the public key to the Alipay console and save both keys locally.
Store the generated private2048.txt, public2048.txt, and Alipay public key files in a rsakey folder inside the Django app.
5. PC‑Side Alipay Payment Interface
Encapsulate the payment logic in a Python class AliPay:
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus, urlparse, parse_qs
from base64 import decodebytes, encodebytes
import json
class AliPay(object):
"""Alipay payment interface (PC side)"""
def __init__(self, appid, app_notify_url, app_private_key_path,
alipay_public_key_path, return_url, debug=False):
self.appid = appid
self.app_notify_url = app_notify_url
self.app_private_key_path = app_private_key_path
self.app_private_key = None
self.return_url = return_url
with open(self.app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
self.alipay_public_key_path = alipay_public_key_path
with open(self.alipay_public_key_path) as fp:
self.alipay_public_key = RSA.importKey(fp.read())
self.__gateway = "https://openapi.alipaydev.com/gateway.do" if debug else "https://openapi.alipay.com/gateway.do"
def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
biz_content = {"subject": subject, "out_trade_no": out_trade_no,
"total_amount": total_amount, "product_code": "FAST_INSTANT_TRADE_PAY"}
biz_content.update(kwargs)
data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
return self.sign_data(data)
def build_body(self, method, biz_content, return_url=None):
data = {"app_id": self.appid, "method": method, "charset": "utf-8",
"sign_type": "RSA2", "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0", "biz_content": biz_content}
if return_url is not None:
data["notify_url"] = self.app_notify_url
data["return_url"] = self.return_url
return data
def sign_data(self, data):
data.pop("sign", None)
unsigned_items = self.ordered_data(data)
unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
sign = self.sign(unsigned_string.encode("utf-8"))
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)
signed_string = quoted_string + "&sign=" + quote_plus(sign)
return signed_string
def ordered_data(self, data):
complex_keys = []
for key, value in data.items():
if isinstance(value, dict):
complex_keys.append(key)
for key in complex_keys:
data[key] = json.dumps(data[key], separators=(",", ":"))
return sorted([(k, v) for k, v in data.items()])
def sign(self, unsigned_string):
signer = PKCS1_v1_5.new(self.app_private_key)
signature = signer.sign(SHA256.new(unsigned_string))
return encodebytes(signature).decode("utf8").replace("
", "")
def _verify(self, raw_content, signature):
signer = PKCS1_v1_5.new(self.alipay_public_key)
digest = SHA256.new()
digest.update(raw_content.encode("utf8"))
return signer.verify(digest, decodebytes(signature.encode("utf8")))
def verify(self, data, signature):
data.pop("sign_type", None)
unsigned_items = self.ordered_data(data)
message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
return self._verify(message, signature)6. Front‑End Pages
Two simple HTML templates are used: index.html to display a product list and show.html to show the payment result.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
table, table tr th, table tr td { border:1px solid #0094ff; }
table { width:300px; min-height:25px; line-height:25px; text-align:center; border-collapse:collapse; padding:2px; }
a{ text-decoration:none; }
</style>
</head>
<body>
<h1>欢迎来到购物商场</h1>
<table border="1">
<thead>商品目录</thead>
<tr><td>商品名</td><td>商品单价</td><td>商品数量</td><td>是否购买</td></tr>
<tr><td>梨子</td><td>0.1</td><td>1</td><td><a href="{% url 'dingdan' %}">购买</a></td></tr>
</table>
</body>
</html> <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>支付结果:{{msg}}</h1>
</body>
</html>7. View Functions
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse
from .pay import AliPay
import uuid
from urllib.parse import parse_qs
def index(request):
return render(request, 'index.html')
def dingdan(request):
alipay = AliPay(appid="YOUR_APPID", app_notify_url='http://127.0.0.1:8000/paypay/check/',
return_url='http://127.0.0.1:8000/paypay/show/',
app_private_key_path=r'C:\path\private2048.txt',
alipay_public_key_path=r'C:\path\paypublic.txt', debug=True)
res = alipay.direct_pay(subject='梨子', out_trade_no=str(uuid.uuid4()), total_amount='0.1')
url = 'https://openapi.alipaydev.com/gateway.do?{0}'.format(res)
return redirect(url)
def show(request):
if request.method == 'GET':
alipay = AliPay(appid="YOUR_APPID", app_notify_url='http://127.0.0.1:8000/paypay/check/',
return_url='http://127.0.0.1:8000/paypay/show/',
app_private_key_path=r'C:\path\private2048.txt',
alipay_public_key_path=r'C:\path\paypublic.txt', debug=True)
param = request.GET.dict()
sign = param.pop('sign', None)
statu = alipay.verify(param, sign)
if statu:
return render(request, 'show.html', {'msg': '支付成功'})
else:
return render(request, 'show.html', {'msg': '支付失败'})
else:
return render(request, 'show.html', {'msg': '只支持GET请求,不支持其它请求'})
def check(request):
if request.method == 'POST':
alipay = AliPay(appid="YOUR_APPID", app_notify_url='http://127.0.0.1:8000/paypay/check/',
return_url='http://127.0.0.1:8000/show_msg/',
app_private_key_path=r'C:\path\private2048.txt',
alipay_public_key_path=r'C:\path\paypublic.txt', debug=True)
body = request.body.decode('utf-8')
post_data = parse_qs(body)
post_dict = {k: v[0] for k, v in post_data.items()}
sign = post_dict.pop('sign', None)
status = alipay.verify(post_dict, sign)
return HttpResponse('支付成功' if status else '支付失败')
else:
return HttpResponse('只支持POST请求')8. URL Routing
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('dingdan/', views.dingdan, name='dingdan'),
path('show/', views.show, name='show'),
path('check/', views.check, name='check'),
]9. Run the Project
After all files are in place, execute python manage.py migrate and python manage.py runserver. Visiting the home page, selecting a product, and clicking “购买” will redirect to the Alipay sandbox payment page, and the result will be displayed on show.html.
10. Summary
The sandbox implementation works, but you must replace the placeholder APPID and upload your own RSA public/private keys before using it in production.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
