• luffy-(13)


    内容概览

    • 支付宝支付介绍
    • 支付宝支付二次封装
    • 订单相关表设计
    • 生成订单接口
    • 支付前端
    • 支付宝回调接口

    支付宝支付介绍

    """
    项目中有需要在线支付功能,可以使用
    	支付宝支付(沙箱环境)
    	微信支付(需要有备案过的域名)
    	云闪付
    
    我们的项目以支付宝支付为例
    	支付流程
    	使用官方或第三方的API/sdk
    		第三方sdk:基于API封装(我们使用这个)
    		官方sdk:https://opendocs.alipay.com/open/02no41
    
    支付宝支付介绍
    	申请条件很严苛
        沙箱环境:Sandbox:程序的虚拟执行环境,不需要申请各种认证,直接写程序,后期只需要换成只是的秘钥即可
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    img

    使用支付宝支付
    1. 使用沙箱环境:https://open.alipay.com/develop/sandbox/app
    2. 第三方的sdk:https://github.com/fzlee/alipay
    	-基于支付宝的API接口封装的,开源软件,
        -pip install python-alipay-sdk
    
    3. 生成公钥私钥:使用支付宝提供的工具
    	-https://opendocs.alipay.com/common/02kipk
    	-生成公钥私钥,在本地(私钥好好保管)
    
    4. 把公钥填在支付宝网站上(沙箱环境/正式环境)
    	-把我们的公钥填进网站,会生成一个支付宝公钥,以后项目中我们使用支付宝公钥来做
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    基本使用

    新建两个文件保存应用私钥与支付宝公钥
    app_private_key.pem,应用私钥

    -----BEGIN RSA PRIVATE KEY-----
    base64 encoded content
    -----END RSA PRIVATE KEY-----
    
    • 1
    • 2
    • 3

    alipay_public_key.pem,支付宝公钥

    -----BEGIN PUBLIC KEY-----
    base64 encoded content
    -----END PUBLIC KEY-----
    
    • 1
    • 2
    • 3
    from alipay import AliPay
    from alipay.utils import AliPayConfig
    
    # 初始化得到对象,传入一堆参数
    alipay = AliPay(
        appid="2016092000554611",  # app的id号
        app_notify_url=None,  # 默认回调 url
        app_private_key_string=open('./app_private_key.pem').read(),   # 应用私钥
        alipay_public_key_string=open('./alipay_public_key.pem').read(),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        sign_type="RSA2",  # RSA 或者 RSA2
        debug=False,  # 默认 False
        verbose=False,  # 输出调试数据
        config=AliPayConfig(timeout=15)  # 可选,请求超时时间
    )
    
    # 生成支付链接
    order_string = alipay.api_alipay_trade_page_pay(
        out_trade_no="订单号(uuid)",
        total_amount=99999,  # 支付金额
        subject='精品内衣',  # 订单标题
        return_url="https://example.com",  # get回调地址(前端)
        notify_url="https://example.com/notify"  # post回调地址(后端)
    )
    # print('https://openapi.alipay.com/gateway.do?'+order_string)  # 真实的地址
    print('https://openapi.alipaydev.com/gateway.do?'+order_string)  # 测试的地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    支付宝支付二次封装

    """
    目录结构
    alipay_common  # 包名
        pem        # 放公钥私钥
        	alipay_public_key.pem
        	app_private_key.pem
        __init__.py 
        pay.py    # 核心文件
        settings.py #配置文件
    """
    
    # 如果保证公钥私钥的安全:
    	1. 不在项目中直接写,写在环境变量中
    	2. 专门写一个公钥私钥管理的服务,发送请求获取,接口携带很多认证
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    pay.py

    from alipay import AliPay
    from alipay.utils import AliPayConfig
    from . import settings
    
    # 初始化得到对象,传入一堆参数
    alipay = AliPay(
        appid=settings.APPID,  # app的id号
        app_notify_url=None,  # 默认回调 url
        app_private_key_string=settings.APP_PRIVATE_KEY_STRING,
        # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_STRING,
        sign_type=settings.SIGN,  # RSA 或者 RSA2
        debug=settings.DEBUG,  # 默认 False
        verbose=False,  # 输出调试数据
        config=AliPayConfig(timeout=15)  # 可选,请求超时时间
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    settings.py

    import os
    
    # 应用ID
    APPID = '2021000121695894'
    # 应用私钥
    APP_PRIVATE_KEY_STRING = open(
        os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'app_private_key.pem')).read()
    # 支付宝公钥
    ALIPAY_PUBLIC_KEY_STRING = open(
        os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'alipay_public_key.pem')).read()
    # 加密方式
    SIGN = 'RSA2'
    
    # 是否是支付宝测试环境(沙箱环境),如果采用真是支付宝环境,配置False
    DEBUG = True
    
    # 支付网关
    GATEWAY = 'https://openapi.alipaydev.com/gateway.do?' if DEBUG else 'https://openapi.alipay.com/gateway.do?'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    init

    from .pay import alipay
    from .settings import GATEWAY
    
    • 1
    • 2

    订单相关表设计

    1. 创建订单app
    ...\apps> python ../../manage.py startapp order
    # 注册app 
    
    2. 设计表
    	-订单表
        -订单详情表 :订单表和订单详情是一对多的关系
    from django.db import models
    from user.models import UserInfo
    from course.models import Course
    
    
    # Create your models here.
    # 订单表
    class Order(models.Model):
        """订单模型"""
        status_choices = (
            (0, '未支付'),
            (1, '已支付'),
            (2, '已取消'),
            (3, '超时取消'),
        )
        pay_choices = (
            (1, '支付宝'),
            (2, '微信支付'),
        )
        subject = models.CharField(max_length=150, verbose_name="订单标题")
        total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总价", default=0)
        # 唯一的,咱们生成的, uuid
        out_trade_no = models.CharField(max_length=64, verbose_name="订单号", unique=True)
        # 支付宝 成功后,会有个流水号
        trade_no = models.CharField(max_length=64, null=True, verbose_name="流水号")
        # 订单状态
        order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="订单状态")
        pay_type = models.SmallIntegerField(choices=pay_choices, default=1, verbose_name="支付方式")
        # 支付时间:支付宝支付完成返回的数据中有这个字段
        pay_time = models.DateTimeField(null=True, verbose_name="支付时间")
        # 订单创建时间,不一定支付
        created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
        user = models.ForeignKey(UserInfo, related_name='order_user', on_delete=models.DO_NOTHING, db_constraint=False,
                                 verbose_name="下单用户")
    
        class Meta:
            db_table = "luffy_order"
            verbose_name = "订单记录"
            verbose_name_plural = "订单记录"
    
        def __str__(self):
            return "%s - ¥%s" % (self.subject, self.total_amount)
    
        @property
        def courses(self):
            data_list = []
            for item in self.order_courses.all():
                data_list.append({
                    "id": item.id,
                    "course_name": item.course.name,
                    "real_price": item.real_price,
                })
            return data_list
    
    
    # 订单详情表
    class OrderDetail(models.Model):
        """订单详情"""
        order = models.ForeignKey(Order, related_name='order_courses', on_delete=models.CASCADE, db_constraint=False,
                                  verbose_name="订单")
        course = models.ForeignKey(Course, related_name='course_orders', on_delete=models.CASCADE, db_constraint=False,
                                   verbose_name="课程")
        price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价")
        real_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程实价")
    
        class Meta:
            db_table = "luffy_order_detail"
            verbose_name = "订单详情"
            verbose_name_plural = "订单详情"
    
        def __str__(self):
            try:
                return "%s的订单:%s" % (self.course.name, self.order.out_trade_no)
            except:
                return super().__str__()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    生成订单接口

    # 前端:点击购买按钮---->向后端发送请求【需要登录认证】,携带数据{courses:[1,2,3],total_amount:999,subject:订单名,pay_type:1}
    
    # 后端:
    	-两个重要的事:生成支付链接,在订单表中插入数据
        -视图类:create;序列化类:数据校验,生成支付链接
    
    • 1
    • 2
    • 3
    • 4
    • 5
    视图类
    from django.shortcuts import render
    from .models import Order
    from .serializers import OrderSerializer
    from utils.response import APIResponse
    from rest_framework.viewsets import GenericViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from rest_framework.permissions import IsAuthenticated
    
    
    # Create your views here.
    
    class OrderView(GenericViewSet):
        queryset = Order.objects.all()
        serializer_class = OrderSerializer
        # 登录后才能够访问
        authentication_classes = [JSONWebTokenAuthentication]
        permission_classes = [IsAuthenticated]
    
        # 这个新增接口,既要新增,又要返回支付链接;重写create方法
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data, context={'request': request})
            serializer.is_valid(raise_exception=True)
            serializer.save()
            pay_url = serializer.context.get('pay_url')
            return APIResponse(pay_url=pay_url)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    序列化类
    import uuid
    
    from rest_framework import serializers
    from .models import Order, OrderDetail
    from rest_framework.exceptions import APIException
    from libs.alipay_common import GATEWAY, alipay
    from django.conf import settings
    from course.models import Course
    
    
    class OrderSerializer(serializers.ModelSerializer):
        # courses不是order表的字段,一定要重写
        # 前端传入的是 courses:[1,3,4]----->转换成课程对象[课程对象1,课程对象3,课程对象4]
        courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True)
    
        class Meta:
            model = Order
            fields = ['courses', 'total_amount', 'subject', 'pay_type']  # 只用来做数据校验和反序列化
    
        def _check_price(self, attrs):
            total_amount = attrs.get('total_amount')
            # 循环所有课程,取出价格累加得到总价格
            real_total = 0
            for course in attrs.get('courses'):
                real_total += course.price
            if not total_amount == real_total:  # 不正常,抛异常
                raise APIException('价格不一致')
            else:
                return real_total
    
        def _get_trade_no(self):
            return str(uuid.uuid4())
    
        def _get_user(self):
            # 当前登录用户,request.user
            request = self.context.get('request')
            return request.user  # 必须通过了登录认证,才有当前登录用户
    
        def _get_pay_url(self, total_amount, subject, trade_no):
    
            pay_str = alipay.api_alipay_trade_page_pay(
                out_trade_no=trade_no,
                total_amount=float(total_amount),
                subject=subject,
                return_url=settings.RETURN_URL,  # get回调地址
                notify_url=settings.NOTIFY_URL  # post回调地址
            )
            return GATEWAY + pay_str
    
        def _before_create(self, pay_url, attrs, user, trade_no):
            self.context['pay_url'] = pay_url
            attrs['user'] = user
            attrs['out_trade_no'] = trade_no
    
        def validate(self, attrs):
            # 1 校验价格:计算一下总价格和后端算出来的总价格是否一致
            total_amount = self._check_price(attrs)
            # 2)生成订单号:唯一的,
            trade_no = self._get_trade_no()
            # 3)支付用户:request.user
            user = self._get_user()
            # 4)支付链接生成,放入到self.context中
            pay_url = self._get_pay_url(total_amount, attrs.get('subject'), trade_no)
            # 5)入库(两个表)的信息准备:重写create方法
            self._before_create(pay_url, attrs, user, trade_no)
    
            return attrs
    
        def create(self, validated_data):
            # {courses:[对象1,对象2],total_amount:11,subject:xx,pay_type:1,user:user,out_trade_no:3333}
            courses = validated_data.pop('courses')
            order = Order.objects.create(**validated_data)
            # 存订单详情表
            for course in courses:
                OrderDetail.objects.create(order=order, course=course, price=course.price, real_price=course.price)
    
            return order
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    路由
    from rest_framework.routers import SimpleRouter
    from . import views
    
    router = SimpleRouter()
    router.register('alipay', views.OrderView, 'alipay')
    urlpatterns = [
    
    ]
    urlpatterns += router.urls
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    配置文件
    # 上线后必须换成公网地址
    # 后台基URL
    HOST_URL = 'http://127.0.0.1:8000'
    # 前台基URL
    LUFFY_URL = 'http://127.0.0.1:8080'
    # 支付宝同步异步回调接口配置
    # 后台异步回调接口 :支付宝post回调地址:后端地址,后端配合一个接口
    NOTIFY_URL = HOST_URL + "/order/success/"
    # 前台同步回调接口,没有 / 结尾 支付宝get回调地址:前端地址,前端配合一个支付成功的页面组件
    RETURN_URL = LUFFY_URL + "/pay/success"
    
    ## jwt配置
    import datetime
    JWT_AUTH = {
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    支付前端

    // 在点击支付按钮添加点击事件
    
    go_buy(price, subject) {
      let token = this.$cookies.get('token')
      if (token) {
        // 发送ajax请求
        this.$axios.post(this.$settings.BASE_URL + 'order/alipay/', {
          courses: [this.course_id],
          total_amount: price,
          subject: subject,
          pay_type: 1
        }, {
          headers: {
            'Authorization': 'jwt ' + token
          }
        }).then(res => {
          if (res.data.code == 100) {
            // 打开支付链接
            open(res.data.pay_url, '_self')
          } else {
            this.$message({
              message: res.data.msg,
              type: 'error'
            });
          }
    
        })
      } else {
        this.$message({
          message: '您没有登录,请先登录',
          type: 'error'
        });
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    支付成功页面PaySuccess.vue
    <template>
      <div class="pay-success">
        
        <Header/>
        <div class="main">
          <div class="title">
            <div class="success-tips">
              <p class="tips">您已成功购买 1 门课程!p>
            div>
          div>
          <div class="order-info">
            <p class="info"><b>订单号:b><span>{{ result.out_trade_no }}span>p>
            <p class="info"><b>交易号:b><span>{{ result.trade_no }}span>p>
            <p class="info"><b>付款时间:b><span><span>{{ result.timestamp }}span>span>p>
          div>
          <div class="study">
            <span>立即学习span>
          div>
        div>
      div>
    template>
    
    <script>
    
    import Header from "@/components/Header"
    
    export default {
      name: "Success",
      data() {
        return {
          result: {},
        };
      },
      created() {
        // url后拼接的参数:?及后面的所有参数 => ?a=1&b=2
        // console.log(location.search);
    
        // 解析支付宝回调的url参数
        // location.search 路径中 ? 后的数据
        let params = location.search.substring(1);  // 去除? ------- a=1&b=2
        let items = params.length ? params.split('&') : [];  // ['a=1', 'b=2']
        //逐个将每一项添加到args对象中
        for (let i = 0; i < items.length; i++) {  // 第一次循环a=1,第二次b=2
          let k_v = items[i].split('=');  // ['a', '1']
          //解码操作,因为查询字符串经过编码的
          if (k_v.length >= 2) {
            // url编码反解 https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E7%BE%8E%E5%A5%B3
            let k = decodeURIComponent(k_v[0]);
            this.result[k] = decodeURIComponent(k_v[1]);
            // 没有url编码反解
            // this.result[k_v[0]] = k_v[1];
          }
    
        }
        // 解析后的结果
        console.log(this.result);
    
    
        // 把地址栏上面的支付结果,再get请求转发给后端
        this.$axios.get(this.$settings.BASE_URL + 'order/success/' + location.search,).then(response => {
          if (response.data.code == 100) {
            alert('支付成功')
          } else {
            alert('暂未收到您的付款,请稍后刷新在试')
          }
        }).catch(() => {
          console.log('支付结果同步失败');
        })
      },
      components: {
        Header,
      }
    }
    script>
    
    <style scoped>
    .main {
      padding: 60px 0;
      margin: 0 auto;
      width: 1200px;
      background: #fff;
    }
    
    .main .title {
      display: flex;
      -ms-flex-align: center;
      align-items: center;
      padding: 25px 40px;
      border-bottom: 1px solid #f2f2f2;
    }
    
    .main .title .success-tips {
      box-sizing: border-box;
    }
    
    .title img {
      vertical-align: middle;
      width: 60px;
      height: 60px;
      margin-right: 40px;
    }
    
    .title .success-tips {
      box-sizing: border-box;
    }
    
    .title .tips {
      font-size: 26px;
      color: #000;
    }
    
    
    .info span {
      color: #ec6730;
    }
    
    .order-info {
      padding: 25px 48px;
      padding-bottom: 15px;
      border-bottom: 1px solid #f2f2f2;
    }
    
    .order-info p {
      display: -ms-flexbox;
      display: flex;
      margin-bottom: 10px;
      font-size: 16px;
    }
    
    .order-info p b {
      font-weight: 400;
      color: #9d9d9d;
      white-space: nowrap;
    }
    
    .study {
      padding: 25px 40px;
    }
    
    .study span {
      display: block;
      width: 140px;
      height: 42px;
      text-align: center;
      line-height: 42px;
      cursor: pointer;
      background: #ffc210;
      border-radius: 6px;
      font-size: 16px;
      color: #fff;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152

    支付宝回调接口

    """
    支付成功,支付号会有两个回调
    	-get 回调,回调给前端
    		-为了保证准确性,支付宝回调会前端后,我们自己向后端发送一个请求,查询一下这个订单是否支付成功
    	
    	-post 回调,回调给后端接口
    		-后端接口,接收支付宝的回调,修改订单状态
    		-支付宝在24小时内,会有8次回掉,防止没有收到
    
    
    后端需要写两个接口:
    	-post回调,给支付宝用
    	-get回调,给前端做二次校验使用
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    from rest_framework.exceptions import APIException
    from utils.common_logger import logger
    from utils.response import APIResponse
    from rest_framework.response import Response
    
    class PaySuccessView(ViewSet):
        def list(self, request):
            try:
                out_trade_no = request.query_params.get('out_trade_no')
                Order.objects.get(out_trade_no=out_trade_no, order_status=1)
                return APIResponse()
            except Exception as e:
                raise APIException('该订单还没支付成功')
    
        def create(self, request):  # 给支付宝用的,写完后无法测试-----》外网无法直接访问到内网
            try:
                # from django.http.request import QueryDict
                # print(type(request.data))
                result_data = request.data.dict()  # 回调回来编码格式是urlencoded,QueryDic对象---》.dict--->转成真正的字典对象
                out_trade_no = result_data.get('out_trade_no')
                signature = result_data.pop('sign')  # 如果是QueryDic对象不允许pop
                from libs import alipay_common
                # 验证签名,result_data和signature验证签名,sdk帮咱们写好了,一定要验证签名
                result = alipay_common.alipay.verify(result_data, signature)
                if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
                    # 完成订单修改:订单状态、流水号、支付时间
                    Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1,
                                                                           pay_time=result_data.get('timestamp'),
                                                                           trade_no=result_data.get('trade_no'))
                    # 完成日志记录
                    logger.warning('%s订单支付成功' % out_trade_no)
                    return Response('success')  # 支付宝要求的格式
                else:
                    logger.error('%s订单支付失败' % out_trade_no)
                    return Response('failed')
            except:
                return Response('failed')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    回顾总结之数据结构:3 链表
    【牛客网-前端笔试题】——vue专项练习
    xv6 进程切换中的锁:MIT6.s081/6.828 lectrue12:Coordination 以及 Lab6 Thread 心得
    Java - SpringBoot整合Shiro之缓存功能
    【云原生之Docker实战】使用Docker部署OpenKM文档管理系统
    http协议详解01——http协议概念及工作流程
    【算法日志】单调栈: 单调栈简介及其应用
    PAT A1004 Counting Leaves
    微信小程序-scroll-view
    红外物理学习笔记 ——第三章
  • 原文地址:https://blog.csdn.net/AL_QX/article/details/127968852