django实现支付宝支付

 

django支付宝支付

新建支付宝应用

# 访问"支付宝开发平台"登录,可以访问开发者中心
https://open.alipay.com/platform/home.htm
# 可以参考"电脑网站支付" 熟悉电脑支付整体流程
https://docs.open.alipay.com/270/105899/

创建应用(使用沙箱环境测试)

按照官方要求生成私钥(可以上支付宝开发平台下载支付宝开发助手)

把生成的app公钥粘贴到沙箱的app中

沙箱环境地址: https://openhome.alipay.com/platform/appDaily.htm?tab=info

查看沙箱账号和密码

支付宝开发地址

支付宝开放平台: https://open.alipay.com/platform/home.htm
支付宝沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info
支付宝开发者文档:https://openhome.alipay.com/developmentDocument.htm
电脑网站支付流程:https://docs.open.alipay.com/270
生成签名:https://docs.open.alipay.com/291/106103/
python-alipay-adk : https://github.com/fzlee/alipay/blob/master/README.zh-hans.md

说明

  • 阿里官方没有提供python对接支付的sdk,但是python库中有非官方的sdk包可以使用
  • python-alipay-adk : https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
  • 使用起来非常简单,只要传入几个必要的参数就可以完成
  • 由于支付对安全要求很高,所以要理解对接支付宝安全的流程: 公钥加密、私钥解密 这八个字

在utils中封装请求支付宝扫码地址url的函数和生成订单id的函数

私钥和公钥可以放在app_private_key.pem 和 alipay_public_key.pem文件中。使用时引入

沙箱环境中 app 私钥
private_key_string= open('app_private_key.pem').read()
支付宝公钥
public_key_string = open( 'alipay_public_key.pem').read()

# -*- coding: utf-8 -*-
import datetime
import os
import random
from alipay import AliPay

private_key_string = '''-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApNZyqxPGS3xs/p6lpgffgnbvELjReMRz3y2WGhynDeY/vwODsafKy7XDvYPvE6iGXegz4vxtJINOBJprPXqamQvPJq20z/R3CZlCsOEy75Pr77ZRGZbMvzVXGkuavnLQoH40FuRbQYMXt8rLR1GnBS+5Bs5tWNfy94f4x4VroEZ80zVDnQEkzy46fmoi6lZ5r6N/7iXFo0fXdFWlvZJ0EDBF0BdSnHz7nSi6gbAix+VRU2mhyxh/C3ziF8GSuffzfolPORAKj/ws/UCLyBEio6OR0LJPPiulEEYR1cOsm784GHqCh+7C8MWoRmF1UWZ7nwVR+87Ezaq+ksxLxlKwYwIDAQABAoIBACc0RdOAgYIEltu8GcP2Lx1MnO+CNXfWqYRkEDYnqGe64mBo0pKXSLlIgsR5M4xmYYbGKkkLJl4vyId5vpXBqjFKSLt3RvDKwOEMjXsKJJYshUne/8zpO8siQZQkdSpknk/9lB/5seaT6jkxR0WwGtw17Hi88e7WdZf/w+CYT++vUNDR3thzhGSzgXvfrWppP4XMDnW75HJY+MgRo591vsbLwuQgEMTRqaroU1i5+ivDRak6KhKsiJ3QKJYUO1a+0AUTZMuoOo1Vhyn1qYiaRASYov73vK0WZDLd5/K8anBxWXKVwxj5IBivXcotrlaEQzvvcdu/HxH6+WT4VKQHq5kCgYEA9VFat/q6hGGoSgP3byl2ZbqohoEB2dGFGwgoXKGt8wO2tLhJCAGeyU4uLRAGTk6eO9qnAVr7ZsGmEQ1yaMOwRmatJLZze9yjQufkKOkInrXvVUebXdvRmeUtJ4l0NqtrmkrNcJw49HNR0pjSOhN6R9BGUd75l/P/hU3yjoFF7n0CgYEArAPz8UDYvq1ZKico2vjrWIrnsDpvDsgx8L+i73LzKrL9B3ZTimW+7wsIcWhQF1s27qMnQFPjKbEuqWOTi92TbV7BYXbAyQND0V+y0Txbfs54rGwB2A+0kVTP+sLA/x0mqnek3P2gAsl4p9A5A37rNGESgM64hLd5NOauH60S8F8CgYAixyzQRf2txNaB37wVY1BoraS0pNdpVN3E7kwijb1GZXFif3nDC8/CBDZhpxLtyRF/tMjWVVqsv6lWY4yjs5Jq+KV1PfRzS91NX+ilsBvLvEk40tUA4mf9pFLZdxAlq/muPwqO+2bLqQmheI7JMvez9J/zfWPvGeVQtbM8ZrFOVQKBgQCY+nr8V5trGGdv4ZuoAi/rcr1SMOWL0+b2ILgbE7PGiaAV/tmU/5+qn7lGgmqYGvrjiB3kS7Z+4aCJ7JDPlqMCZX692wrguhKaJe21v2Pvhlgzn2qUaINBrJe6f3F8cMRuXjE0iCrBz8OKGthZj4pF7v6xpybagQE+VtkMOrPZKQKBgDQh5Q4510y+ta+mFPb3tum4cXKBAUeRTS6+Us/0wvNVGpvnPGKzIcP+rGXlAO0Nl7O/PTBgejcIILjcS9AuyxPSfSWhlt5DjjzeQ8/J4yrgVAwQeNC28jkmnKBe5K3R+++Si++nYq4/nZ1WEyyginFf2nvQrW2G+rkzMOKvtRn/
-----END RSA PRIVATE KEY-----'''


publice_key_string = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNZyqxPGS3xs/p6lpyVImg1XELjReMRz3y2WGhynDeY/vwODsafKy7XDvYPvE6iGasegz4vxtJINOBJprPXqamQvPJq20z/R3CZlCsOEy75Pr77ZRGZbMvzVXGkuavnLQoH40FuRbQYMXt8rLR1GnBS+5Bs5tWNfy94f4x4VroEZ80zVDnQEkzy46fmoi6lZ5r6N/7iXFo0fXdFWlvZJ0EDBF0BdSnHz7nSi6gbAix+VRU2mhyxh/C3ziF8GSuffzfolPORAKj/ws/UCLyBEio6OR0LJPPiulEEYR1cOsm784GHqCh+7C8MWoRmF1UWZ7nwVR+87Ezaq+ksxLxlKwYwIDAQAB
-----END PUBLIC KEY-----'''

# udbble1952@sandbox.com
## 获取支付宝url
def get_alipay_url(order_id, order_amount, subject):
    alipay = AliPay(
    appid="888888888888", # 沙箱appid
    app_notify_url=None, # 默认回调url
    app_private_key_string=private_key_string,
    # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
    alipay_public_key_string=publice_key_string,
    sign_type="RSA2", # RSA 或者 RSA2
    debug=True, # 默认False,我们是沙箱,所以改成True(让访问沙箱环境支付宝地址)
    )
    # 调用支付接口
    # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string
    order_string = alipay.api_alipay_trade_page_pay(
    out_trade_no=order_id, # 订单id,应该从前端获取生成链接地址如下
    total_amount=str(order_amount), # 订单总金额
    subject=subject, # 付款标题信息
    return_url='http://127.0.0.1:8888/payment/callback/', # 付款成功回调地址(可以为空)
    notify_url=None # 付款成功后异步通知地址(可以为空)
    )
    pay_url = "https://openapi.alipaydev.com/gateway.do?" + order_string
    return pay_url # 将这个url复制到浏览器,就会打开支付宝支付页面


# 获取订单唯一id
def get_order_id():
    """
    SYL202008241212121200005/24
    生成订单号: 格式: SYL + 年月日时分秒 + 5位随机数
    :return:
    """
    d = datetime.datetime.now()
    base = 'SYL'
    time_str = '%04d%02d%02d%02d%02d%02d' % (d.year, d.month, d.day, d.hour,
    d.minute, d.second)
    # 1.4 syl/setings.py中配置支付相关参数
    # 2.测试
    # 请求地址
    # 携带参数
    # 返回数据
    rand_num = str(random.randint(10000, 99999))
    return base + time_str + rand_num

 

在model.py中定义表

from django.db import models
from utils.MyBaseModel import Base
# Create your models here.


# 商品表
class Goods(Base):
    GOODS_TYPE = (
        ("1", "vip"),
        ("2", "Course")
    )
    CHANNEL_TYPE = (
        ("1", "普通"),
        ("2", "促销")
    )
    course = models.OneToOneField('course.Course', on_delete=models.PROTECT)
    goods_type = models.CharField("商品种类", choices=GOODS_TYPE, max_length=8)
    product_id = models.CharField("产品id", max_length=8)
    title = models.CharField("商品名称", max_length=24)
    price = models.DecimalField("商品价格", max_digits=8, decimal_places=2)
    channel_type = models.CharField("购买渠道", choices=CHANNEL_TYPE, max_length=8)
    period = models.IntegerField("有效期", default=365)
    is_launched = models.BooleanField("是否上架", default=True)

    class Meta:
        db_table = "tb_goods"

    def __str__(self):
        return self.title


# 订单表
class Orders(Base):
    PAY_METHOD = (
        ("1", "支付宝"),
    )
    ORDER_STATUS = (
        ("1", "待支付"),
        ("2", "已支付"),
        ("3", "已取消")
    )
    user = models.ForeignKey('user.User', on_delete=models.PROTECT, verbose_name="下单用户")
    goods = models.ForeignKey(Goods, on_delete=models.PROTECT)
    order_id = models.CharField("订单号", max_length=24)
    trade_no = models.CharField("支付订单号", max_length=32, null=True)
    pay_time = models.DateTimeField("支付时间", null=True)
    pay_method = models.CharField("支付方式", choices=PAY_METHOD, default=1, max_length=8)
    status = models.CharField("支付状态", choices=ORDER_STATUS, default=1, max_length=8)
    total_amout = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")

    class Meta:
        db_table = "tb_orders"

    def __str__(self):
        return self.order_id


# 用户购买课程表
class UserCourse(Base):
    user = models.ForeignKey('user.User', on_delete=models.CASCADE)
    course = models.ForeignKey('course.Course', on_delete=models.CASCADE)

    class Meta:
        db_table = "usercourse"

    def __str__(self):
        return "用户%s购买的%s" % (self.user, self.course)

 

在views.py中获取支付宝支付的url的接口和回调接口

from decimal import Decimal
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Goods, Orders, UserCourse
from .serializers import GoodsModelSer, OrdersModelSer
from .util import get_order_id, get_alipay_url
from course.models import Course


# 获取支付宝扫码页面的url
class Get_Pay_url(APIView):

    def post(self,request):
        # 根据前端发送的商品id获取对应的商品信息
        goods_id = request.data.get("goods_id")
        goods_obj = Goods.objects.get(pk=goods_id)
        # 获取用户信息
        user = request.user

        # 判断用户的身份对应进行打折
        if user.vip.vip_type == "3":
            goods_price = (goods_obj.price * Decimal('0.60')).quantize(Decimal('0.00'))
        elif user.vip.vip_type == "2":
            goods_price = (goods_obj.price * Decimal('0.80')).quantize(Decimal('0.00'))
        else:
            goods_price = goods_obj.price

        # 存入数据库
        order = Orders(
            user= user,
            goods= goods_obj,
            order_id= get_order_id(),  # 调用在util.py中写的函数获取商品订单id
            pay_method= 1,
            status= 1,
            total_amout= goods_price,
        )
        order.save()

        subject = "实验楼订单:%s,价格:%s" % (order.order_id, goods_price)
        # 调用util中的获取支付宝路由的函数并把自己生成的订单id
        pay_url = get_alipay_url(order_id=order.order_id, order_amount=order.total_amout, subject=subject)

        return Response({"code":200, "msg": "成功", "data": {"pay_url": pay_url}})


"""
 # 前端回调返回的数据
 { "charset": "utf-8",
  "out_trade_no": "SYL2020101508522512986",     # 我们自己生成的订单id
   "method": "alipay.trade.page.pay.return",
    "total_amount": "100.00",                    # 支付价格
    "sign": "HFfe2xBFw/jY8XaJdzuUnqWg9+wPS/PdH7GGigNRScVhfxF94lm2id1eURP/TdvWs4F2HRukJ0Rf/UNzrz4QG18EKiT68ChGrZvIiZHaONY2ok/ix5r68IkQM/7yCB+YF4NrkHDuw92Iy7mLrdKNkOan3+uLgocNuWDTNWo4hT5gCFTxOPPrrWDSJmanX3RPI6HrLsOWUpTcZjhQafAKK0S6Y+bl+MtgfLPV7+hcMesItb/pvsHDRPD1j63VkGuP2mXwW3eDCns3LCn1YfWqjwmutXGqbLEK0HG9NgOKFBL9N6+lBE2lJqfdSo79vMY9cv7287ZvC1b07cygLXMVDA==",
    "trade_no": "2020101522001458970501542142",  # 支付宝的支付id
    "auth_app_id": "2016103000778269",           
    "version": "1.0", 
    "app_id": "2016103000778269", 
    "sign_type": "RSA2", 
    "seller_id": "2088102181451641", 
    "timestamp": "2020-10-15 16:52:56"           # 支付时间
    }
"""
# 支付宝回调地址
class PeyMent(APIView):

    def post(self, request):
        # 获取前端发送的数据
        order_id = request.data.get("out_trade_no")  # 自己生成的订单id
        trade_no = request.data.get("trade_no")      # 支付宝返回的支付宝订单id
        pay_time = request.data.get("timestamp")     # 创建时间

        # 根据订单id获取到对应的订单信息
        orders = Orders.objects.get(order_id=order_id)
        # 修改订单状态,支付时间,支付宝的订单id
        orders.trade_no = trade_no
        orders.pay_time = pay_time
        orders.status = 2
        orders.save()

        # 根据订单获取到对应的商品然后获取到对应的课程
        course_obj = Course.objects.get(pk=orders.goods.course_id)
        # 存到用户购买课程表中
        user = UserCourse(user=request.user, course=course_obj)
        user.save()

        return Response({"code":200, "msg": "支付成功"})

 

前端vue

生成订单, 获取支付链接

// 生成订单, 获取支付链接
    pay() {
      // goods_id: 课程id
      payurl_post({ goods_id: this.goods.id }).then((resp) => {
        console.log(resp)
        let pay_url = resp.data.pay_url
        // debugger
        window.location = pay_url
      })
    },

 

回调页面

<template>
  <div>
    这里是支付回调地址, 把数据发送给后端
    参数是:
    {{query}}
    <p>
      支付结果是: {{msg}}
    </p>
  </div>
</template>
<script>

import { payment_post } from './axios_api/api';
export default {
  data() {
    return {
      query: '',
      msg: '', //支付结果
    }
  },
  mounted() {
    this.query = this.$route.query
    payment_post(this.query).then((resp) => {
      // ({"code": 999, "msg": "非法请求"})
      this.msg = resp.msg
    })
  },

}
</script>

 

 
 
 
posted @ 2020-10-15 22:51  高登汗  阅读(507)  评论(0编辑  收藏  举报