Django对接支付宝实现支付宝充值金币功能示例


Posted in Python onDecember 17, 2019

很多网站里都有金币、积分之类的虚拟货币,获取这些往往需要充值。那么问题来了,如何在Django中对接支付宝实现支付宝充值金币的功能呢?网上很多资料都是电商的,那些都会带有订单系统之类比较复杂,而充值金币功能不需要实现那么多功能。

效果图如下:

Django对接支付宝实现支付宝充值金币功能示例

Django对接支付宝实现支付宝充值金币功能示例

Django对接支付宝实现支付宝充值金币功能示例

现在就来实现Django对接支付宝支付功能吧!

登录支付宝开放平台

点击进入蚂蚁金服开放平台https://open.alipay.com/platform/home.htm

进入支付宝沙箱环境https://openhome.alipay.com/platform/appDaily.htm?tab=info

Django对接支付宝实现支付宝充值金币功能示例

如图,这里是你沙箱环境的配置,左侧沙箱工具有沙箱支付宝安卓版下载,沙箱账号是你的测试账号。

下载支付宝开放平台开发助手

点击打开下载链接

Django对接支付宝实现支付宝充值金币功能示例

打开工具,生成密钥,然后妥善保管好!!

Django对接支付宝实现支付宝充值金币功能示例

Django对接支付宝实现支付宝充值金币功能示例

保存密钥

Django对接支付宝实现支付宝充值金币功能示例

把刚刚那个应用公钥2048重命名为:pub_2048.txt,把应用私钥2048重命名为:private_2048.txt,把这两个文件放在项目目录下。

注意:密钥的开始和结束一定要加上如下的字符串!!!

-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----

Django对接支付宝实现支付宝充值金币功能示例

复制支付宝的公钥并保存

Django对接支付宝实现支付宝充值金币功能示例

把这段支付宝公钥复制,重命名为alipay_key_2048.txt,保存到项目目录中,注意加上如下字符串

-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----

设置公钥

把刚刚的pub_2048.txt里面的字符串复制到如下:

Django对接支付宝实现支付宝充值金币功能示例

调试支付宝支付接口

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)

如果输出的url能够打开并且使用沙箱账号支付,说明前面的配置成功了,可以进行视图的编写。

设计数据库订单模型

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

注意充值的金额要设置为models.DecimalField货币类型

然后导入到数据库中

视图函数编写

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()

当用户付款成功后,会跳转回来,那个就是return_url,处理这个的是get方法,用来更新用户的金币和订单。

以上这篇Django对接支付宝实现支付宝充值金币功能示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python模块之StringIO使用示例
Apr 08 Python
Python中每次处理一个字符的5种方法
May 21 Python
对于Python中RawString的理解介绍
Jul 07 Python
给你选择Python语言实现机器学习算法的三大理由
Nov 15 Python
python2与python3共存问题的解决方法
Sep 18 Python
Python多项式回归的实现方法
Mar 11 Python
浅谈python的输入输出,注释,基本数据类型
Apr 02 Python
Python实现朴素贝叶斯的学习与分类过程解析
Aug 24 Python
python操作openpyxl导出Excel 设置单元格格式及合并处理代码实例
Aug 27 Python
pytorch对梯度进行可视化进行梯度检查教程
Feb 04 Python
用Python 执行cmd命令
Dec 18 Python
Python办公自动化PPT批量转换操作
Sep 15 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 #Python
Django项目使用ckeditor详解(不使用admin)
Dec 17 #Python
python主线程与子线程的结束顺序实例解析
Dec 17 #Python
Django通用类视图实现忘记密码重置密码功能示例
Dec 17 #Python
Django集成celery发送异步邮件实例
Dec 17 #Python
python学生信息管理系统实现代码
Dec 17 #Python
pymysql模块的操作实例
Dec 17 #Python
You might like
PHP MVC模式在网站架构中的实现分析
2010/03/04 PHP
PHP生成指定长度随机数最简洁的方法
2014/07/14 PHP
PHP 导出Excel示例分享
2014/08/18 PHP
Smarty使用自定义资源的方法
2015/08/08 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
javascript代码加载优化方法
2011/01/30 Javascript
jQuery LigerUI 使用教程表格篇(1)
2012/01/18 Javascript
JS小功能(button选择颜色)简单实例
2013/11/29 Javascript
jQuery之过滤元素操作小结
2013/11/30 Javascript
JQuery中serialize()、serializeArray()和param()方法示例介绍
2014/07/31 Javascript
javascript面向对象之this关键词用法分析
2015/01/13 Javascript
JavaScript包装对象使用详解
2015/07/09 Javascript
JS实现带提示的星级评分效果完整实例
2015/10/30 Javascript
jQuery页面加载初始化的3种方法(推荐)
2016/06/02 Javascript
vue 使用html2canvas将DOM转化为图片的方法
2018/09/11 Javascript
深入浅析Vue.js 中的 v-for 列表渲染指令
2018/11/19 Javascript
Python中实现远程调用(RPC、RMI)简单例子
2014/04/28 Python
python中利用h5py模块读取h5文件中的主键方法
2018/06/05 Python
Python实现自定义函数的5种常见形式分析
2018/06/16 Python
Python中使用遍历在列表中添加字典遇到的坑
2019/02/27 Python
python3.7 使用pymssql往sqlserver插入数据的方法
2019/07/08 Python
Pytorch中的variable, tensor与numpy相互转化的方法
2019/10/10 Python
浅谈Tensorflow加载Vgg预训练模型的几个注意事项
2020/05/26 Python
Python中的Cookie模块如何使用
2020/06/04 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
2020/06/30 Python
浅谈python 类方法/静态方法
2020/09/18 Python
python如何利用paramiko执行服务器命令
2020/11/07 Python
python 实现简易的记事本
2020/11/30 Python
俄罗斯珠宝市场的领导者之一:Бронницкий ювелир
2019/10/02 全球购物
汽车技术服务与营销专业推荐信
2013/11/29 职场文书
会计系个人求职信范文分享
2013/12/20 职场文书
班主任经验交流会主持词
2014/04/01 职场文书
2014年教师节座谈会发言稿
2014/09/10 职场文书
简易版租房协议书范本
2014/10/13 职场文书
故意杀人罪辩护词
2015/05/21 职场文书
python中opencv实现图片文本倾斜校正
2021/06/11 Python