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实现的金山快盘的签到程序
Jan 17 Python
Python使用smtplib模块发送电子邮件的流程详解
Jun 27 Python
Python自动生产表情包
Mar 17 Python
Python实现模拟分割大文件及多线程处理的方法
Oct 10 Python
Python 多进程并发操作中进程池Pool的实例
Nov 01 Python
实用自动化运维Python脚本分享
Jun 04 Python
python redis 批量设置过期key过程解析
Nov 26 Python
在tensorflow中实现去除不足一个batch的数据
Jan 20 Python
使用Python三角函数公式计算三角形的夹角案例
Apr 15 Python
使用Keras预训练模型ResNet50进行图像分类方式
May 23 Python
Alpine安装Python3依赖出现的问题及解决方法
Dec 25 Python
pd.DataFrame中的几种索引变换的实现
Jun 16 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 header()函数使用说明
2008/07/10 PHP
单点登录 Ucenter示例分析
2013/10/29 PHP
Joomla语言翻译类Jtext用法分析
2016/05/05 PHP
PHP 使用二进制保存用户状态的实例
2018/01/29 PHP
PHP精确到毫秒秒杀倒计时实例详解
2019/03/14 PHP
Firefox div高度自适应
2009/04/28 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
NodeJS 模块开发及发布详解分享
2012/03/07 NodeJs
固定表格行列(expression)在IE下适用
2013/07/25 Javascript
jQuery 如何先创建、再修改、后添加DOM元素
2014/05/20 Javascript
Bootstrap3 多选和单选框(checkbox)
2016/12/29 Javascript
详解angular ui-grid之过滤器设置
2017/06/07 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
浅谈vue中使用图片懒加载vue-lazyload插件详细指南
2017/10/23 Javascript
react native 原生模块桥接的简单说明小结
2019/02/26 Javascript
微信公众号H5之微信分享常见错误和问题(小结)
2019/11/14 Javascript
微信小程序 flexbox layout快速实现基本布局的解决方案
2020/03/24 Javascript
解决vue一个页面中复用同一个echarts组件的问题
2020/07/19 Javascript
js实现Element中input组件的部分功能并封装成组件(实例代码)
2021/03/02 Javascript
[00:27]DOTA2次级职业联赛 - Lilith战队宣传片
2014/12/01 DOTA
九步学会Python装饰器
2015/05/09 Python
实例解析Python的Twisted框架中Deferred对象的用法
2016/05/25 Python
Python中新式类与经典类的区别详析
2019/07/10 Python
Django实现发送邮件找回密码功能
2019/08/12 Python
Python django框架开发发布会签到系统(web开发)
2020/02/12 Python
如何导出python安装的所有模块名称和版本号到文件中
2020/06/05 Python
python中判断数字是否为质数的实例讲解
2020/12/06 Python
美国在线乐器和设备商店:Musician’s Friend
2018/07/06 全球购物
巴西本土电商平台:Americanas
2020/06/21 全球购物
我想声明一个指针并为它分配一些空间, 但却不行。这些代码有什么 问题?char *p; *p = malloc(10);
2016/10/06 面试题
图书室管理制度
2014/01/19 职场文书
在校大学生的职业生涯规划书
2014/03/14 职场文书
大学班级文化建设方案
2014/05/06 职场文书
广告艺术设计专业自荐书
2014/07/08 职场文书
投资意向协议书
2015/01/29 职场文书
2016干部作风整顿心得体会
2016/01/22 职场文书