vue+drf没公网ip接入支付宝功能

自己没有公网ip接入支付宝

技术是vue+drf

  • vue–主要看创建订单和修改订单支付状态

    balanceCount () { // 结算
              if(this.addrInfo.length==0){
                  alert("请选择收货地址")
              }else{
                createOrder(
                  {
                    post_script:this.post_script,
                    address:this.address,
                    signer_name:this.signer_name,
                    signer_mobile:this.signer_mobile,
                    order_mount:this.totalPrice
                  }
                ).then((response)=> {
                  alert('订单创建成功');
                  window.location.href=response.data.alipay_url;
                  updateOrder(
                    {
                      "order_id": response.data.id
                    }
                  ).then((response)=>{
                      alert("订单修改成功");
                    }).catch(function (error) {
                      console.log(error);
                  });
                }).catch(function (error) {
                  console.log(error);
                });
    
  • api–只看创建订单和修改订单支付状态

    
    //添加订单
    export const createOrder = params => {return axios.post(`${local_host}/orders/`, params)}
    
    //订单更新
    export const updateOrder = params => {return axios.post(`${local_host}/check_pay/`, params)}
    
  • 订单序列化–创建订单时去支付宝支付, 所以在序列化类里要创建个alipay_url

    class OrderSerializer(serializers.ModelSerializer):
        """
        订单信息序列化类
        """
    
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
    
        add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M:%S")
    
        # read_only只返回不提交
        # write_only只提交不反回
        pay_status = serializers.CharField(read_only=True)
    
        order_sn = serializers.CharField(read_only=True)
    
        trade_no = serializers.CharField(read_only=True)
    
        # order_mount = serializers.FloatField(read_only=True)
    
        pay_time = serializers.DateTimeField(read_only=True)
    
        # SerializerMethodField 这是一个只读字段。它通过在附加的序列化器类上调用一个方法来获取其值。它可以用于将任何类型的数据添加到对象的序列化表示中。
        # read_only 只返回不提交
        alipay_url = serializers.SerializerMethodField(read_only=True)
    
        def get_alipay_url(self, obj):
            alipay = AliPay(
                appid="",  # 沙箱appid 或 线上appid
                app_notify_url=None,  # 默认回调url  不写的话这里用None
                # os.path.dirname(__file__): 获取当前文件所在目录的路径
                app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"),  # 私钥
                alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),
                # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False   沙箱环境把这里设置为True
            )
    
            url = alipay.api_alipay_trade_page_pay(
                out_trade_no=obj.order_sn,  # 订单id
                total_amount=str(obj.order_mount),  # 支付总金额(这里用str 它内部自动将它转换成json)
                subject=obj.order_sn,  # 订单标题
            )
            return 'https://openapi.alipaydev.com/gateway.do?' + url
    
        def generate_order_sn(self):
            """
            生成订单号
            :return:
            """
            from random import Random
            random_ins = Random()
    
            # 当前时间+userid+随机数
            # 当前时间并且格式化time.strftime("%Y%m%d%H%M%S")
            # self.request.user.id当前用户的id
            # random_ins.randint(10, 99)生成两位的随机数
    
            order_sn = "%s%s%s" % (time.strftime("%Y%m%d%H%M%S"), self.context["request"].user.id, random_ins.randint(10, 99))
    
            return order_sn
    
        def validate(self, attrs):
            print("attrs", attrs)
            attrs["order_sn"] = self.generate_order_sn()
            return attrs
    
        class Meta:
            model = OrderInfo
            fields = "__all__"
    
  • 订单详情序列化–订单的详情页面点击去支付, 所以在序列化类里要创建个alipay_url

    class OrderDetailSerializer(serializers.ModelSerializer):
        """
        订单详情序列化类
        """
    
        goods = OrderGoodsSerializer(many=True)
    
        # SerializerMethodField 这是一个只读字段。它通过在附加的序列化器类上调用一个方法来获取其值。它可以用于将任何类型的数据添加到对象的序列化表示中。
        # read_only 只返回不提交
        alipay_url = serializers.SerializerMethodField(read_only=True)
    
        def get_alipay_url(self, obj):
            alipay = AliPay(
                appid="",  # 沙箱appid 或 线上appid
                app_notify_url=None,  # 默认回调url  不写的话这里用None
                # os.path.dirname(__file__): 获取当前文件所在目录的路径
                app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"),  # 私钥
                alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),
                # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False   沙箱环境把这里设置为True
            )
    
            url = alipay.api_alipay_trade_page_pay(
                out_trade_no=obj.order_sn,  # 订单id
                total_amount=str(obj.order_mount),  # 支付总金额(这里用str 它内部自动将它转换成json)
                subject=obj.order_sn,  # 订单标题
            )
            return 'https://openapi.alipaydev.com/gateway.do?' + url
    
        class Meta:
            model = OrderInfo
            fields = "__all__"
    
  • view–订单

    class OrderViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
        """
        订单管理
            create:
                创建订单
            list:
                获取订单信息
            delete:
                取消订单
            retrieve:
                查看订单详细信息
        """
    
        # 动态指定序列化类
        def get_serializer_class(self):
            if self.action == "retrieve":
                return OrderDetailSerializer
    
            return OrderSerializer
    
        # IsAuthenticated指定权限, 用户登入才能访问
        # IsOwnerOrReadOnly总是允许GET、HEAD或OPTIONS请求, 其他请求判断当前操作的数据它的user是否为当前用户
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    
        # json token的验证  局部大于全局, 就算你在全局设置过, 但是你只要在这里加上authentication_classes 就会替换全局设置
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    
        def get_queryset(self):
            return OrderInfo.objects.filter(user=self.request.user)
    
        def perform_create(self, serializer):
            """
            保存序列化信息
            :param serializer: 序列化类
            :return: 序列化关联的model的实例
            """
            # 想在保存之前做点操作, 就重写perform_create方法
            # 想在创建时做点操作, 就重写create方法
    
            order = serializer.save()
    
            # 1. 把购物车信息保存到OrderGoods模型类里面
            shop_carts = ShoppingCart.objects.filter(user=self.request.user)
            for shop_cart in shop_carts:
                order_goods = OrderGoods.objects.create(goods=shop_cart.goods, goods_num=shop_cart.nums, order=order)
                order_goods.save()
    
            # 2. 清空购物车
            shop_carts.delete()
    
            # 3. 返回订单信息
            return order
    
  • view-checkpay

    class CheckPayView(APIView):
        def post(self, request):
            # 业务处理:使用python SDK调用支付宝的支付接口
            # 初始化
            order_id = request.data.get("order_id", None)
    
            try:
                order = OrderInfo.objects.get(id=order_id)
            except OrderInfo.DoesNotExist:
                return Response({"order": "无效id"}, status=status.HTTP_404_NOT_FOUND)
    
            alipay = AliPay(
                appid="2016092500596768",  # 使用支付宝沙箱的id(你有实际的id就用实际的)
                app_notify_url=None,  # 默认回调url
                app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"),  # 应用私钥路径
                # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
                alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),  # 支付宝公钥路径
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=True  # 默认False(这里用的沙箱所以是True 实际开发是False)
            )
    
            # 调用支付宝的交易查询接口
            while True:
                response = alipay.api_alipay_trade_query(order.order_sn)
    
                # 返回的response就是这样的一个字典
                # response = {
                #     "trade_no": "2017032121001004070200176844", # 支付宝交易号
                #     "code": "10000", # 接口调用是否成功
                #     "invoice_amount": "20.00",
                #     "open_id": "20880072506750308812798160715407",
                #     "fund_bill_list": [
                #       {
                #         "amount": "20.00",
                #         "fund_channel": "ALIPAYACCOUNT"
                #       }
                #     ],
                #     "buyer_logon_id": "csq***@sandbox.com",
                #     "send_pay_date": "2017-03-21 13:29:17",
                #     "receipt_amount": "20.00",
                #     "out_trade_no": "out_trade_no15",
                #     "buyer_pay_amount": "20.00",
                #     "buyer_user_id": "2088102169481075",
                #     "msg": "Success",
                #     "point_amount": "0.00",
                #     "trade_status": "TRADE_SUCCESS", # 支付结果
                #     "total_amount": "20.00"
                # }
    
                # response里的 code是10000(表示调用成功) 20000(表示不成功) 20001(授权权限不足) 40001(缺少必要的参数) 40002(非法参数)
                # 40004(业务处理失败) 40006(权限不足)
    
                # response里的 trade_status值为TRADE_SUCCESS(交易支付成功) WAIT_BUYER_PAY(交易创建,等待买家付款)、
                # TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_FINISHED(交易结束,不可退款)
    
                code = response.get('code')
    
                trade_status = response.get('trade_status')
    
                if code == '10000' and trade_status == 'TRADE_SUCCESS':
    
                    # 支付成功
                    # 获取支付宝交易号
                    trade_no = response.get('trade_no')
    
                    # 更新订单的状态
                    order.trade_no = trade_no
    
                    order.pay_time = datetime.now()
    
                    order.pay_status = "success"
    
                    order.save()
    
                    # 返回结果
                    from django.shortcuts import redirect
                    response = redirect("index")
                    # 设置cookie 最长时间为2秒
                    response.set_cookie("nextPath", "pay", max_age=2)
                    return Response("success")
                elif code == '40004' or (code == '10000' and trade_status == 'WAIT_BUYER_PAY'):
                    # 等待买家付款
                    # 业务处理失败, 可能一会就会成功
                    import time
                    time.sleep(5)
                    continue
                else:
                    return Response("failure")
    
  • url

    from rest_framework.routers import DefaultRouter
    
    from trade.views import OrderViewSet, CheckPayView
    
    # 生成一个注册器实例对象
    router = DefaultRouter()
    
    # 订单
    router.register(r"orders", OrderViewSet, base_name="orders")
    
    urlpatterns = [
        # 自动生成url
        url(r"^", include(router.urls)),
    
        url(r"^check_pay/$", CheckPayView.as_view(), name="check_pay"),
    ]
    
  • 效果图
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本季课程把开发知识拆解到项目里,让你在项目情境里学知识。这样的学习方式能让你保持兴趣、充满动力,时刻知道学的东西能用在哪、能怎么用。平时不明白的知识点,放在项目里去理解就恍然大悟了。  一、融汇贯通本视频采用了前后端分离的开发模式,前端使用Vue.js+Element UI实现了Web页面的呈现,后端使用Python 的Django REST Framework框架实现了数据访问的接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端的各自承担的工作。 二、贴近实战本课程为学生信息管理系统课程:Vue3 + Vite + ElementPlus + Django REST Framework项目实战 本季课程主学生信息管理系统V5.0,内容包含:Django REST framework安装和项目初始化、数据的序列化、ViewSet视图集、DefaultRouter路由类、django-filter实现过滤、rest framework实现查找、rest framework实现分页、npm的使用、使用Vite构建vue3项目、Package.json解析、ElementPlus安装和应用、vue-router实现路由、使用Vuex的store对象、后台管理系统主界面的布局、axios组件的安装和请求、axios请求的模块化、请求拦截器和响应拦截器、使用el-select实现联级下拉、使用cascader实现联级选择、vue表单的验证、实现学生信息的添加、修改和删除、实现文件的上传等等功能 本案例完整的演示了项目实现过程,虽然不复杂,但涉及的内容非常多,特别是前后端交互的时候,有诸多的坑等着你去踩,好在王老师全程代码呈现,带着大家一起填坑,大大提高学习效率的同时,也培养了大家良好的代码习惯,希望大家一起跟着王进老师学习Python开发。三、后续课程预告:Vue和Django REST Framework实现JWT登录认证 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只因为你温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值