Many sites are in gold, like the integration of virtual currency, to obtain these often need to recharge. So the question is, how to achieve docking payment function Po Alipay gold in Django it? Lot of information online are electricity providers, who will order the system with such complex, gold and recharge functions required to implement so versatile.
The effect is as follows:
Django now to achieve docking Alipay feature it!
Log Alipay open platform
Click to enter ants gold dress open platform https://open.alipay.com/platform/home.htm
enter Alipay sandbox environment https://openhome.alipay.com/platform/appDaily.htm?tab=info
As shown, this is to configure your sandbox environment, on the left there is a sandbox sandbox tool Alipay Android version download, sandbox account is your test account.
Download Alipay open platform development assistant
Click to open the download link
Open the tool, generate keys, and then take good care of! !
Save the key
The public key 2048 that application just rename: pub_2048.txt
, 2048 to rename the application of the private key: private_2048.txt
, these two files in the project directory.
Note: The start and end keys must add the following string! ! !
-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----
Copy the public key Alipay and save
Alipay public put this copy, rename alipay_key_2048.txt, saved to the project directory, add the following string note
-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----
Setting Public Key
To just a pub_2048.txt
copy of the string to the inside as follows:
Alipay debug interfaces
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
from base64 import decodebytes, encodebytes
import json
class AliPay(object):
"""
支付宝支付接口
"""
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.import_key(fp.read())
if debug is True:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "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",
# "qr_pay_mode":4
}
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"))
# ordered_items = self.ordered_data(data)
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)
# 将字典类型的数据dump出来
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):
# 开始计算签名
key = self.app_private_key
signer = PKCS1_v1_5.new(key)
signature = signer.sign(SHA256.new(unsigned_string))
# base64 编码,转换为unicode表示并移除回车
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign
def _verify(self, raw_content, signature):
# 开始计算签名
key = self.alipay_public_key
signer = PKCS1_v1_5.new(key)
digest = SHA256.new()
digest.update(raw_content.encode("utf8"))
if signer.verify(digest, decodebytes(signature.encode("utf8"))):
return True
return False
def verify(self, data, signature):
if "sign_type" in data:
sign_type = data.pop("sign_type")
# 排序后的字符串
unsigned_items = self.ordered_data(data)
message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
return self._verify(message, signature)
def get_alipay_url(app_id, order_sn, order_mount):
alipay = AliPay(
appid=app_id,
app_notify_url="http://127.0.0.1:8000/alipay/return/",
app_private_key_path="../trade/keys/private_2048.txt",
alipay_public_key_path="../trade/keys/alipay_key_2048.txt", # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
debug=True, # 默认False,
return_url="http://127.0.0.1:8000/alipay/return/"
)
url = alipay.direct_pay(
subject=order_sn,
out_trade_no=order_sn,
total_amount=order_mount,
)
re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)
return re_url
if __name__ == "__main__":
url = get_alipay_url(
'2016092600597838',
'201902923423436',
1.00
)
print(url)
If the url output can open and use the sandbox account to pay, the foregoing description is configured, it can be written in the view.
Orders database design model
from django.db import models
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from questioning.utils.models import CreatedUpdatedMixin
@python_2_unicode_compatible
class OrderInfo(CreatedUpdatedMixin, models.Model):
'''
充值订单详情
'''
ORDER_STATUS = (
('TRADE_SUCCESS', '交易支付成功'),
('TRADE_CLOSED', '未付款交易超时关闭'),
('WAIT_BUYER_PAY', '交易创建'),
('TRADE_FINISHED', '交易结束'),
('paying', '待支付'),
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='用户')
order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name='订单号')
trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name='支付订单号')
pay_status = models.CharField(choices=ORDER_STATUS, max_length=40, verbose_name='订单状态', default='paying')
order_mount = models.DecimalField(verbose_name="充值金额", max_digits=10,
decimal_places=2, default=0.00)
class Meta:
verbose_name = "充值订单"
verbose_name_plural = verbose_name
def __str__(self):
return self.order_sn
Note recharge amount to be set to the models.DecimalField
currency type
and then imported into the database
View Writing functions
class AlipayView(LoginRequiredMixin, AuthorRequiredMixin, View):
"""
支付宝支付
get方法实现支付宝return_url,如果没有实现也无所谓,post同样可以更新状态
post方法实现支付宝notify_url,异步更新
支付宝返回的url如下:
#http://127.0.0.1:8000/alipay/return/?
# charset=utf-8&
# out_trade_no=201902923423436&
# method=alipay.trade.page.pay.return&
# total_amount=1.00&
# sign=CDBMY9NBsp4KICdQoBEVxGWobd0N8y4%2BU09stzUWwlNtLr7ZpELJdM5js20wXv%2FCPp0FGPbRW1YS9DRx0CnKJULZZMqysBUMH2FL39sS0Fgstgy1ydTs7ySXdHziJV0inI%2BDWAsebQqtjk5gQEweUstc%2B%2BnzjdgAulpvWzfJsbknS%2BqUfktSdF2ZOWGhr1CFlfsMFEDS2nzQv4K3E%2BNaeylkzUnRe9M1sjIL%2FYR0wVZ5A3OfHLPf9HzC2B8%2FLu4g7N5Vctkqp2aerDvIkN5SNmDnRGyjOt2b%2BOsLMqG4X06JSsrZT6Ln8PimsrkSOIGbj0gCqscx7BwZfmCQePlCw%3D%3D&
# trade_no=2019082622001426981000041778&
# auth_app_id=2016092600597838&
# version=1.0&app_id=2016092600597838&
# sign_type=RSA2&
# seller_id=2088102177296610&
# timestamp=2019-08-26+13%3A51%3A01
"""
def dispatch(self, request, *args, **kwargs):
self.alipay = AliPay(
appid=settings.ALIPAY_APPID,
app_notify_url=settings.APP_NOTIFY_URL,
app_private_key_path=settings.APP_PRIVATE_KEY_PATH,
alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH,
debug=settings.ALIPAY_DEBUG,
return_url=settings.RETURN_URL
)
#处理返回的url参数
callback_data = {}
for key, value in request.GET.items():
callback_data[key] = value
sign = callback_data.pop('sign', None)
self.order_sn = callback_data.get('out_trade_no', None) #订单号
self.trade_no = callback_data.get('trade_no', None) #支付宝订单号
# 验证签名
self.verify = self.alipay.verify(callback_data, sign)
return super(AlipayView, self).dispatch(request, *args, **kwargs)
def get(self, request):
"""处理支付宝return_url返回"""
if self.verify:
self.deposit()
#返回个人中心页面
return redirect(reverse('users:detail', kwargs={
'username': request.user.username
}))
def post(self, request):
"""
处理notify_url
"""
if self.verify:
self.deposit()
return Response('success')
def deposit(self):
"""充值操作
1.更新用户的金币信息
2.更新订单状态为交易成功
"""
# 数据库中查询订单记录
order = OrderInfo.objects.get(order_sn=self.order_sn)
order.trade_no = self.trade_no # 支付宝订单号
# 把人民币转换成对应的金币
rmb = order.order_mount
money = convert_rmb_to_money(rmb)
# 更新用户的金币
order.user.money += Decimal(money)
order.user.save()
# 订单状态置为交易成功
order.pay_status = 'TRADE_SUCCESS'
order.save()
When the user payment is successful, it will jump back, that is return_url, to deal with this is to get the method used to update the user's gold and order.