python代码上传minio、fastdfs 、搜索后台接口、搜索前台、付宝支付介绍 、 支付宝二次封装、下单接口

python代码上传minio、fastdfs

python代码上传minio

# pip install minio

from minio import Minio
from minio.error import S3Error

# 使用endpoint、access key和secret key来初始化minioClient对象。
client = Minio(
    "192.168.1.252:9000",
    access_key="H4AFY3DTXKX5WTMSIVJG",
    secret_key="O0AbX04NTXHqYzaBQiNR2u4+D1TGAL+AKsBRW64x",
    secure=False
)
# 调用make_bucket来创建一个存储桶。
# minioClient.make_bucket("maylogs", location="us-east-1")
# test02 为桶名字
res = client.fput_object("test11", "zxj1.jpg", "./7.jpg")
print(res.object_name)
print('文件地址为【文件在浏览器打开会直接下载,放到index.html 中使用img引入查看】:\n',
      'http://192.168.1.252:9000/test02/' + res.object_name)

python代码上传fastdfs

client.conf

connect_timeout=30
network_timeout=60
tracker_server = 192.168.1.252:22122
http.tracker_server_port = 8888

main.py

# pip3 install py3Fdfs
from fdfs_client.client import get_tracker_conf, Fdfs_client

tracker_conf = get_tracker_conf('./client.conf')
client = Fdfs_client(tracker_conf)

#文件上传
result = client.upload_by_filename('./7.jpg')
print(result)
# {'Group name': b'group1', 'Remote file_id': b'group1/M00/00/00/rBMGZWCeGhqAR_vRAAIAABZebgw.sqlite', 'Status': 'Upload successed.', 'Local file name': './db.sqlite3', 'Uploaded size': '128.00KB', 'Storage IP': b'101.133.225.166'}
# 访问地址即可下载:http://192.168.1.252:8888/group1/M00/00/00/CgAAzmSihyKAUybqAAH8LXKkrrY060.jpg


#文件下载
# result = client.download_to_file('./lqz.sqlite', b'group1/M00/00/00/rBMGZWCeGxaAFWqfAAIAABZebgw.sqlite')
# print(result)


# #文件删除
# result = client.delete_file(b'group1/M00/00/00/rBMGZWCeGhqAR_vRAAIAABZebgw.sqlite')
# print(result)
# ('Delete file successed.', b'group1/M00/00/00/rBMGZWCeGhqAR_vRAAIAABZebgw.sqlite', b'192.168.1.252')

# #列出所有的group信息
result = client.list_all_groups()
print(result)


搜索后台接口

1.此次写的很简单,但是公司中这个接口是最牛逼的
	搜索接口中带个性化推荐
    
2.此次只写了实战课,搜索要搜索所有跟用户输入相关的
	1.实战课
  2.轻课
  3.免费
  4.资料 文档  
  

视图类

from rest_framework.filters import SearchFilter
class SearchCourseView(GenericViewSet,ListModelMixin):
    serializer_class = CourseSerializer
    queryset = Course.objects.filter(is_delete=False,is_show = True).order_by('orders').all()
    filter_backends = [SearchFilter]
    search_fields = ['name', "brief"]  # brief内容非常多,如果使用mysql的搜索,like 全文搜,随着数据量越来越大,搜索越来越慢--->分布式全文检索引擎

伪代码:搜索要搜索所有跟课程输入相关的

    def list(self, request, *args, **kwargs):
         res=super().list(request, *args, **kwargs)
         actual_course=res.data.data   # [{},{}]
         free_course=[{},{},{}]
         light_course=[{},{},{}]
         others=[{},{},{}]
         return APIResponse(actual_course=actual_course,free_course=free_course)

搜索前台

Header.vue

<template>
  <div class="header">
    <div class="slogan">
      <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
    </div>
    <div class="nav">
      <ul class="left-part">
        <li class="logo">
          <router-link to="/">
            <img src="../assets/img/head-logo.svg" alt="">
          </router-link>
        </li>
        <li class="ele">
          <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
        </li>
        <li class="ele">
          <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
        </li>
        <li class="ele">
          <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
        </li>
      </ul>

      <div class="right-part">
        <div v-if="username">
          <span>{{ username }}</span>
          <span class="line">|</span>
          <span @click="handleLogout">注销</span>

        </div>
        <div v-else>
          <span @click="put_login">登录</span>
          <span class="line">|</span>
          <span @click="put_register">注册</span>

        </div>
        <Login v-if="is_login" @close="close_login" @go="put_register"/>
        <Register v-if="is_register" @close="close_register" @go="put_login"/>


      </div>
      <form class="search">
        <div class="tips" v-if="is_search_tip">
          <span @click="search_action('Python')">Python</span>
          <span @click="search_action('Linux')">Linux</span>
        </div>
        <input type="text" :placeholder="search_placeholder" @focus="on_search" @blur="off_search"
               v-model="search_word">
        <el-button icon="el-icon-search" circle @click="search_action(search_word)"></el-button>
      </form>

    </div>
  </div>

</template>

<script>
import Login from "@/components/Login";
import Register from "@/components/Register";

export default {
  name: "Header",
  data() {
    return {
      url_path: sessionStorage.url_path || '/',
      is_login: false,
      is_register: false,
      username: '',
      is_search_tip: true,
      search_placeholder: '',
      search_word: ''
    }
  },
  methods: {

    search_action(search_word) {
      if (!search_word) {
        this.$message('请输入要搜索的内容');
        return
      }
      if (search_word !== this.$route.query.word) {
        this.$router.push(`/course/search?word=${search_word}`);
      }
      this.search_word = '';
    },
    on_search() {
      this.search_placeholder = '请输入想搜索的课程';
      this.is_search_tip = false;
    },
    off_search() {
      this.search_placeholder = '';
      this.is_search_tip = true;
    },

    goPage(url_path) {
      // 已经是当前路由就没有必要重新跳转
      if (this.url_path !== url_path) {
        this.$router.push(url_path);
      }
      sessionStorage.url_path = url_path;
    },
    put_login() {
      this.is_login = true;
      this.is_register = false;
    },
    put_register() {
      this.is_login = false;
      this.is_register = true;
    },
    close_login() {
      this.is_login = false;
      // 子组件触发了它,需要取出username显示出来
      this.username = this.$cookies.get('username')

    },
    close_register() {
      this.is_register = false;
    },
    handleLogout() {
      // 前后端分离后,退出只需要清除浏览器中的登录记录即可,不需要再向后端发送请,除非后端想记录用户的退出操作,可以配合个接口
      this.$cookies.remove('username')
      this.$cookies.remove('token')
      this.$cookies.remove('icon')
      this.username = ''
    }
  },
  created() {
    sessionStorage.url_path = this.$route.path;  // '/'    ’/freeCourse‘
    this.url_path = this.$route.path;
    this.username = this.$cookies.get('username')
  },
  components: {
    Login, Register
  }
}
</script>

<style scoped>
.header {
  background-color: white;
  box-shadow: 0 0 5px 0 #aaa;
}

.header:after {
  content: "";
  display: block;
  clear: both;
}

.slogan {
  background-color: #eee;
  height: 40px;
}

.slogan p {
  width: 1200px;
  margin: 0 auto;
  color: #aaa;
  font-size: 13px;
  line-height: 40px;
}

.nav {
  background-color: white;
  user-select: none;
  width: 1200px;
  margin: 0 auto;

}

.nav ul {
  padding: 15px 0;
  float: left;
}

.nav ul:after {
  clear: both;
  content: '';
  display: block;
}

.nav ul li {
  float: left;
}

.logo {
  margin-right: 20px;
}

.ele {
  margin: 0 20px;
}

.ele span {
  display: block;
  font: 15px/36px '微软雅黑';
  border-bottom: 2px solid transparent;
  cursor: pointer;
}

.ele span:hover {
  border-bottom-color: orange;
}

.ele span.active {
  color: orange;
  border-bottom-color: orange;
}

.right-part {
  float: right;
}

.right-part .line {
  margin: 0 10px;
}

.right-part span {
  line-height: 68px;
  cursor: pointer;
}

.search {
  float: right;
  position: relative;
  margin-top: 22px;
  margin-right: 10px;
}

.search input, .search button {
  border: none;
  outline: none;
  background-color: white;
}

.search input {
  border-bottom: 1px solid #eeeeee;
}

.search input:focus {
  border-bottom-color: orange;
}

.search input:focus + button {
  color: orange;
}

.search .tips {
  position: absolute;
  left: 0;
}

.search .tips span {
  border-radius: 11px;
  background-color: #eee;
  line-height: 22px;
  display: inline-block;
  padding: 0 7px;
  margin-right: 3px;
  cursor: pointer;
  color: #aaa;
  font-size: 14px;

}

.search .tips span:hover {
  color: orange;
}

</style>

SearchCourse.vue

<template>
  <div class="search-course course">
    <Header/>

    <!-- 课程列表 -->
    <div class="main">
      <div v-if="course_list.length > 0" class="course-list">
        <div class="course-item" v-for="course in course_list" :key="course.name">
          <div class="course-image">
            <img :src="course.course_img" alt="">
          </div>
          <div class="course-info">
            <h3>
              <router-link :to="'/free/detail/'+course.id">{{ course.name }}</router-link>
              <span><img src="@/assets/img/avatar1.svg" alt="">{{ course.students }}人已加入学习</span></h3>
            <p class="teather-info">
              {{ course.teacher.name }} {{ course.teacher.title }} {{ course.teacher.signature }}
              <span
                  v-if="course.sections>course.pub_sections">共{{ course.sections }}课时/已更新{{ course.pub_sections }}课时</span>
              <span v-else>共{{ course.sections }}课时/更新完成</span>
            </p>
            <ul class="section-list">
              <li v-for="(section, key) in course.section_list" :key="section.name"><span
                  class="section-title">0{{ key + 1 }}  |  {{ section.name }}</span>
                <span class="free" v-if="section.free_trail">免费</span></li>
            </ul>
            <div class="pay-box">
              <div v-if="course.discount_type">
                <span class="discount-type">{{ course.discount_type }}</span>
                <span class="discount-price">¥{{ course.real_price }}元</span>
                <span class="original-price">原价:{{ course.price }}元</span>
              </div>
              <span v-else class="discount-price">¥{{ course.price }}元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
      </div>
      <div v-else style="text-align: center; line-height: 60px">
        没有搜索结果
      </div>
      <div class="course_pagination block">
        <el-pagination
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page.sync="filter.page"
            :page-sizes="[3, 5]"
            :page-size="filter.page_size"
            layout="sizes, prev, pager, next"
            :total="course_total">
        </el-pagination>
      </div>
    </div>
  </div>
</template>

<script>
import Header from '../components/Header'

export default {
  name: "SearchCourse",
  components: {
    Header,
  },
  data() {
    return {
      course_list: [],
      course_total: 0,
      filter: {
        page_size: 10,
        page: 1,
        search: '',
      }
    }
  },
  created() {
    this.get_course()
  },
  watch: {
    '$route.query'() {
      this.get_course()
    }
  },
  methods: {
    handleSizeChange(val) {
      // 每页数据量发生变化时执行的方法
      this.filter.page = 1;
      this.filter.page_size = val;
    },
    handleCurrentChange(val) {
      // 页码发生变化时执行的方法
      this.filter.page = val;
    },
    get_course() {
      // 获取搜索的关键字
      this.filter.search = this.$route.query.word

      // 获取课程列表信息
      this.$axios.get(`${this.$settings.BASE_URL}course/search/`, {
        params: this.filter
      }).then(response => {
        if (response.data.code == 100) {
          // 如果后台不分页,数据在response.data中;如果后台分页,数据在response.data.results中
          this.course_list = response.data.data.results;
          this.course_total = response.data.data.count;
        }

      }).catch(() => {
        this.$message({
          message: "获取课程信息有误,请联系客服工作人员"
        })
      })
    }
  }
}
</script>

<style scoped>
.course {
  background: #f6f6f6;
}

.course .main {
  width: 1100px;
  margin: 35px auto 0;
}

.course .condition {
  margin-bottom: 35px;
  padding: 25px 30px 25px 20px;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 2px 4px 0 #f0f0f0;
}

.course .cate-list {
  border-bottom: 1px solid #333;
  border-bottom-color: rgba(51, 51, 51, .05);
  padding-bottom: 18px;
  margin-bottom: 17px;
}

.course .cate-list::after {
  content: "";
  display: block;
  clear: both;
}

.course .cate-list li {
  float: left;
  font-size: 16px;
  padding: 6px 15px;
  line-height: 16px;
  margin-left: 14px;
  position: relative;
  transition: all .3s ease;
  cursor: pointer;
  color: #4a4a4a;
  border: 1px solid transparent; /* transparent 透明 */
}

.course .cate-list .title {
  color: #888;
  margin-left: 0;
  letter-spacing: .36px;
  padding: 0;
  line-height: 28px;
}

.course .cate-list .this {
  color: #ffc210;
  border: 1px solid #ffc210 !important;
  border-radius: 30px;
}

.course .ordering::after {
  content: "";
  display: block;
  clear: both;
}

.course .ordering ul {
  float: left;
}

.course .ordering ul::after {
  content: "";
  display: block;
  clear: both;
}

.course .ordering .condition-result {
  float: right;
  font-size: 14px;
  color: #9b9b9b;
  line-height: 28px;
}

.course .ordering ul li {
  float: left;
  padding: 6px 15px;
  line-height: 16px;
  margin-left: 14px;
  position: relative;
  transition: all .3s ease;
  cursor: pointer;
  color: #4a4a4a;
}

.course .ordering .title {
  font-size: 16px;
  color: #888;
  letter-spacing: .36px;
  margin-left: 0;
  padding: 0;
  line-height: 28px;
}

.course .ordering .this {
  color: #ffc210;
}

.course .ordering .price {
  position: relative;
}

.course .ordering .price::before,
.course .ordering .price::after {
  cursor: pointer;
  content: "";
  display: block;
  width: 0px;
  height: 0px;
  border: 5px solid transparent;
  position: absolute;
  right: 0;
}

.course .ordering .price::before {
  border-bottom: 5px solid #aaa;
  margin-bottom: 2px;
  top: 2px;
}

.course .ordering .price::after {
  border-top: 5px solid #aaa;
  bottom: 2px;
}

.course .ordering .price_up::before {
  border-bottom-color: #ffc210;
}

.course .ordering .price_down::after {
  border-top-color: #ffc210;
}

.course .course-item:hover {
  box-shadow: 4px 6px 16px rgba(0, 0, 0, .5);
}

.course .course-item {
  width: 1100px;
  background: #fff;
  padding: 20px 30px 20px 20px;
  margin-bottom: 35px;
  border-radius: 2px;
  cursor: pointer;
  box-shadow: 2px 3px 16px rgba(0, 0, 0, .1);
  /* css3.0 过渡动画 hover 事件操作 */
  transition: all .2s ease;
}

.course .course-item::after {
  content: "";
  display: block;
  clear: both;
}

/* 顶级元素 父级元素  当前元素{} */
.course .course-item .course-image {
  float: left;
  width: 423px;
  height: 210px;
  margin-right: 30px;
}

.course .course-item .course-image img {
  max-width: 100%;
  max-height: 210px;
}

.course .course-item .course-info {
  float: left;
  width: 596px;
}

.course-item .course-info h3 a {
  font-size: 26px;
  color: #333;
  font-weight: normal;
  margin-bottom: 8px;
}

.course-item .course-info h3 span {
  font-size: 14px;
  color: #9b9b9b;
  float: right;
  margin-top: 14px;
}

.course-item .course-info h3 span img {
  width: 11px;
  height: auto;
  margin-right: 7px;
}

.course-item .course-info .teather-info {
  font-size: 14px;
  color: #9b9b9b;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid #333;
  border-bottom-color: rgba(51, 51, 51, .05);
}

.course-item .course-info .teather-info span {
  float: right;
}

.course-item .section-list::after {
  content: "";
  display: block;
  clear: both;
}

.course-item .section-list li {
  float: left;
  width: 44%;
  font-size: 14px;
  color: #666;
  padding-left: 22px;
  /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
  background: url("/src/assets/img/play-icon-gray.svg") no-repeat left 4px;
  margin-bottom: 15px;
}

.course-item .section-list li .section-title {
  /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  display: inline-block;
  max-width: 200px;
}

.course-item .section-list li:hover {
  background-image: url("/src/assets/img/play-icon-yellow.svg");
  color: #ffc210;
}

.course-item .section-list li .free {
  width: 34px;
  height: 20px;
  color: #fd7b4d;
  vertical-align: super;
  margin-left: 10px;
  border: 1px solid #fd7b4d;
  border-radius: 2px;
  text-align: center;
  font-size: 13px;
  white-space: nowrap;
}

.course-item .section-list li:hover .free {
  color: #ffc210;
  border-color: #ffc210;
}

.course-item {
  position: relative;
}

.course-item .pay-box {
  position: absolute;
  bottom: 20px;
  width: 600px;
}

.course-item .pay-box::after {
  content: "";
  display: block;
  clear: both;
}

.course-item .pay-box .discount-type {
  padding: 6px 10px;
  font-size: 16px;
  color: #fff;
  text-align: center;
  margin-right: 8px;
  background: #fa6240;
  border: 1px solid #fa6240;
  border-radius: 10px 0 10px 0;
  float: left;
}

.course-item .pay-box .discount-price {
  font-size: 24px;
  color: #fa6240;
  float: left;
}

.course-item .pay-box .original-price {
  text-decoration: line-through;
  font-size: 14px;
  color: #9b9b9b;
  margin-left: 10px;
  float: left;
  margin-top: 10px;
}

.course-item .pay-box .buy-now {
  width: 120px;
  height: 38px;
  background: transparent;
  color: #fa6240;
  font-size: 16px;
  border: 1px solid #fd7b4d;
  border-radius: 3px;
  transition: all .2s ease-in-out;
  float: right;
  text-align: center;
  line-height: 38px;
  position: absolute;
  right: 0;
  bottom: 5px;
}

.course-item .pay-box .buy-now:hover {
  color: #fff;
  background: #ffc210;
  border: 1px solid #ffc210;
}

.course .course_pagination {
  margin-bottom: 60px;
  text-align: center;
}
</style>

支付宝支付介绍

1.购买课程,付款--->支付宝支付
	1.支付宝支付(即便没有账号,也可以测试)
  2.微信支付(需要用营业执照申请商家帐号)
  3.银联支付
    
2.支付宝支付介绍
  1.支付宝API:六大接口
  https://docs.open.alipay.com/270/105900/

  2.支付宝工作流程(见下图):
  https://docs.open.alipay.com/270/105898/

  3.支付宝8次异步通知机制(支付宝对我们服务器发送POST请求,索要 success 7个字符)
  https://docs.open.alipay.com/270/105902/

    
3.集成支付宝流程
	1.我们自己的网站:点击购买按钮--->向我们后端发送请求--->携带购买商品信息--->生成订单,入库,订单是未支付状态----->生成支付宝支付链接---->返回给前端
   2.前端拿到支付链接--->get请求打开---->咱们的前端就来到了支付宝的页面--->用户掏出手机扫描支付--->付款完成---->支付宝收到了钱---->get回调(咱们配置回调地址)---->跳回我们自己的网页--->支付宝还会发送post请求给我们后端---->我们要验签,通过后,把订单状态改为已支付状态
    
4.使用第三方sdk
	1.基于官方的api封装的
    pip install python-alipay-sdk --upgrade
    gitee开源框架:https://github.com/fzlee/alipay

image

1.要使用支付宝:需要营业执照注册,没有的话,可以使用沙箱环境测试,测试通过,后期只要换成公司的商户号和支付宝公钥私钥即可
2.沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info
3.需要生成公钥私钥:非对称加密--->公钥加密,私钥解密
	https://opendocs.alipay.com/common/02kipl
	ps:把你的公钥,配置在支付宝账号里,生成支付宝公钥---->写支付,需要用支付宝公钥和私钥

4.电脑网站支付API:https://docs.open.alipay.com/270/105900/
5.完成RSA密钥生成:https://docs.open.alipay.com/291/105971
6.在开发中心的沙箱应用下设置应用公钥:填入生成的公钥文件中的内容
7.Python支付宝开源框架:https://github.com/fzlee/alipay
	pip install python-alipay-sdk --upgrade
8.公钥私钥设置
    """
    # alipay_public_key.pem
    -----BEGIN PUBLIC KEY-----
    支付宝公钥
    -----END PUBLIC KEY-----

    # app_private_key.pem
    -----BEGIN RSA PRIVATE KEY-----
    用户私钥
    -----END RSA PRIVATE KEY-----
    """
9.支付宝链接
  """
  开发:https://openapi.alipay.com/gateway.do
  沙箱:https://openapi.alipaydev.com/gateway.do
  """

步骤

1.命令:pip install python-alipay-sdk --upgrade

2.创建文件夹

libs
    ├── iPay  							# aliapy二次封装包
    │   ├── __init__.py 				# 包文件
    │   ├── pem							# 公钥私钥文件夹
    │   │   ├── alipay_public_key.pem	# 支付宝公钥文件
    │   │   ├── app_private_key.pem		# 应用私钥文件
    │   ├── pay.py						# 支付文件
    └── └── settings.py  				# 应用配置  

3.代码

pay.py

from alipay import AliPay, DCAliPay, ISVAliPay
from alipay.utils import AliPayConfig

# 支付宝网页下载的证书不能直接被使用,需要加上头尾
# 你可以在此处找到例子: tests/certs/ali/ali_private_key.pem

app_private_key_string = open("./pem/app_private_key.pem").read()
alipay_public_key_string = open("./pem/alipay_public_key.pem").read()

alipay = AliPay(
    appid="9021000122698943",    # # 支付宝页面上复制,沙箱环境--->公司有人会给你
    app_notify_url=None,  # 默认回调 url
    app_private_key_string=app_private_key_string,
    # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
    alipay_public_key_string=alipay_public_key_string,
    sign_type="RSA2",  # RSA 或者 RSA2
    debug=False,  # 默认 False
    verbose=False,  # 输出调试数据
    config=AliPayConfig(timeout=15)  # 可选,请求超时时间
)


# 如果你是 Python3 的用户,使用默认的字符串即可
subject = "纪梵希"

# 电脑网站支付,需要跳转到:https://openapi.alipay.com/gateway.do? + order_string
order_string = alipay.api_alipay_trade_page_pay(
    out_trade_no="20161112fsgfhbfx",
    total_amount=100,
    subject=subject,
    return_url="https://example.com",
    notify_url="https://example.com/notify" # 可选,不填则使用默认 notify url

)
print('https://openapi-sandbox.dl.alipaydev.com/gateway.do?'+order_string)  # 支付宝网管地址+order_string

app_private_key.pem

    -----BEGIN RSA PRIVATE KEY-----
    用户私钥
    -----END RSA PRIVATE KEY-----

alipay_public_key.pem

    -----BEGIN PUBLIC KEY-----
    支付宝公钥
    -----END PUBLIC KEY-----

支付宝二次封装

libs
	-alipay_common
		--pem
			---alipay_public_key.pem
			---app_private_key.pem
		--__init__.py
		--pay.py
		--settings.py

settings.py

import os

# 应用私钥
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()

# 应用ID
APP_ID = "9021000122698943"

# 加密方式
SIGN_TYPE ="RSA2"

# 是否是支付宝测试环境(沙箱环境),如果采用真是支付宝环境,配置False
DEBUG=True

# 支付网关
GATEWAY = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?' if DEBUG else 'https://openapi-sandbox.dl.alipay.com/gateway.do?'

pay.py

from alipay import AliPay
from alipay.utils import AliPayConfig
from . import settings

# 支付宝网页下载的证书不能直接被使用,需要加上头尾
# 你可以在此处找到例子: tests/certs/ali/ali_private_key.pem
app_private_key_string = settings.APP_PRIVATE_KEY_STRING
alipay_public_key_string = settings.ALIPAY_PUBLIC_KEY_STRING

alipay = AliPay(
    appid=settings.APP_ID,    # # 支付宝页面上复制,沙箱环境--->公司有人会给你
    app_notify_url=None,  # 默认回调 url
    app_private_key_string=app_private_key_string,
    # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
    alipay_public_key_string=alipay_public_key_string,
    sign_type=settings.SIGN_TYPE,  # RSA 或者 RSA2
    debug=settings.DEBUG,  # 默认 False
    verbose=False,  # 输出调试数据
    config=AliPayConfig(timeout=15)  # 可选,请求超时时间
)

# 支付网关
gateway = settings.GATEWAY

视图

from rest_framework.views import APIView
from libs.alipay_common import alipay,gateway
from utils.common_response import APIResponse

class AliPyaView(APIView):
    def get(self,request,*args,**kwargs):
        subject = "纪梵希"
        # 电脑网站支付,需要跳转到:https://openapi.alipay.com/gateway.do? + order_string
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no="efreafrf",
            total_amount=100,
            subject=subject,
            return_url="https://example.com",
            notify_url="https://example.com/notify"  # 可选,不填则使用默认 notify url
        )
        pay_url=gateway + order_string
        print(pay_url)
        return APIResponse(pay_url=pay_url)
      
ps:浏览器访问:http://127.0.0.1:8000/api/v1/order/test/

下单接口

数据插入



INSERT INTO `luffy_banner` VALUES (1, '2022-04-20 12:26:39.334880', '2022-04-24 10:21:50.320108', 0, 1, 1, 'banner1', 'banner/banner1.png', 'http://www.cnblogs.com', '首页1');
INSERT INTO `luffy_banner` VALUES (2, '2022-04-20 12:26:59.822785', '2022-04-20 12:26:59.822810', 0, 1, 2, 'banner2', 'banner/banner2.png', '/home', 'banner2');
INSERT INTO `luffy_banner` VALUES (3, '2022-04-20 12:27:18.959757', '2022-04-20 12:27:18.959781', 0, 1, 3, 'banner3', 'banner/banner3.png', '/home', 'banner3');
INSERT INTO `luffy_banner` VALUES (4, '2022-04-20 12:27:38.829129', '2022-04-20 12:27:38.829159', 0, 1, 4, 'banner4', 'banner/banner4.png', '/home', 'banner4');


INSERT INTO `luffy_course` VALUES (1, '2019-07-14 13:54:33.095201', '2022-04-28 12:36:32.603852', 0, 1, 1, 'Python开发21天入门', 'courses/alex_python.png', 0, 'Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土&&&Python从入门到入土', 0, '2019-07-14', 21, '', 0, 231, 120, 120, 199.00, 1, 1);
INSERT INTO `luffy_course` VALUES (2, '2019-07-14 13:56:05.051103', '2019-07-14 13:56:05.051142', 0, 1, 2, 'Python项目实战', 'courses/mjj_python.png', 0, '', 1, '2019-07-14', 30, '', 0, 340, 120, 120, 99.00, 1, 2);
INSERT INTO `luffy_course` VALUES (3, '2019-07-14 13:57:21.190053', '2019-07-14 13:57:21.190095', 0, 1, 3, 'Linux系统基础5周入门精讲', 'courses/lyy_linux.png', 0, '', 0, '2019-07-14', 25, '', 0, 219, 100, 100, 39.00, 2, 3);
INSERT INTO `luffy_course` VALUES (4, '2022-04-28 12:06:36.564933', '2022-04-28 12:36:04.812789', 0, 1, 4, 'DRF从入门到放弃', 'courses/drf.png', 0, 'drf很牛逼', 4, '2022-04-28', 7, '', 0, 399, 0, 0, 77.00, 1, 1);
INSERT INTO `luffy_course` VALUES (5, '2022-04-28 12:35:44.319734', '2022-04-28 12:35:44.319757', 0, 1, 5, 'Go语言从入门到入坑', 'courses/msbd.png', 0, 'Go语言从入门到入坑Go语言从入门到入坑Go语言从入门到入坑Go语言从入门到入坑', 0, '2022-04-28', 20, '', 0, 30, 200, 100, 66.00, 3, 1);
INSERT INTO `luffy_course` VALUES (6, '2022-04-28 12:39:55.562716', '2022-04-28 12:39:55.562741', 0, 1, 6, 'Go语言微服务', 'courses/celery.png', 0, 'Go语言微服务Go语言微服务Go语言微服务Go语言微服务', 4, '2022-04-28', 7, '', 0, 122, 0, 0, 299.00, 3, 2);



INSERT INTO `luffy_course_category` VALUES (1, '2019-07-14 13:40:58.690413', '2019-07-14 13:40:58.690477', 0, 1, 1, 'Python');
INSERT INTO `luffy_course_category` VALUES (2, '2019-07-14 13:41:08.249735', '2019-07-14 13:41:08.249817', 0, 1, 2, 'Linux');
INSERT INTO `luffy_course_category` VALUES (3, '2022-04-28 12:07:33.314057', '2022-04-28 12:07:33.314088', 0, 1, 3, 'Go语言');


INSERT INTO `luffy_course_chapter` VALUES (1, '2019-07-14 13:58:34.867005', '2019-07-14 14:00:58.276541', 0, 1, 1, 1, '计算机原理', '', '2019-07-14', 1);
INSERT INTO `luffy_course_chapter` VALUES (2, '2019-07-14 13:58:48.051543', '2019-07-14 14:01:22.024206', 0, 1, 2, 2, '环境搭建', '', '2019-07-14', 1);
INSERT INTO `luffy_course_chapter` VALUES (3, '2019-07-14 13:59:09.878183', '2022-04-29 10:11:45.744898', 0, 1, 1, 1, '项目创建', '', '2019-07-14', 2);
INSERT INTO `luffy_course_chapter` VALUES (4, '2019-07-14 13:59:37.448626', '2019-07-14 14:01:58.709652', 0, 1, 4, 1, 'Linux环境创建', '', '2019-07-14', 3);
INSERT INTO `luffy_course_chapter` VALUES (5, '2022-04-28 12:08:36.679922', '2022-04-28 12:08:36.680014', 0, 1, 2, 2, 'Linux5周第二章', 'Linux5周第二章Linux5周第二章Linux5周第二章Linux5周第二章Linux5周第二章', '2022-04-28', 3);
INSERT INTO `luffy_course_chapter` VALUES (6, '2022-04-28 12:09:19.324504', '2022-04-28 12:09:19.324533', 0, 1, 2, 2, 'py实战项目第二章', 'py实战项目第二章py实战项目第二章py实战项目第二章py实战项目第二章', '2022-04-28', 2);
INSERT INTO `luffy_course_chapter` VALUES (7, '2022-04-28 12:09:32.532905', '2022-04-29 10:11:57.546455', 0, 1, 3, 3, 'py实战项目第三章', 'py实战项目第三章py实战项目第三章py实战项目第三章', '2022-04-28', 2);
INSERT INTO `luffy_course_chapter` VALUES (8, '2022-04-28 12:09:55.496622', '2022-04-28 12:09:55.496686', 0, 1, 1, 1, 'drf入门1', 'drf入门1drf入门1drf入门1', '2022-04-28', 4);
INSERT INTO `luffy_course_chapter` VALUES (9, '2022-04-28 12:10:08.490618', '2022-04-28 12:10:08.490642', 0, 1, 2, 2, 'drf入门2', 'drf入门drf入门1drf入门1drf入门1drf入门1', '2022-04-28', 4);
INSERT INTO `luffy_course_chapter` VALUES (10, '2022-04-28 12:10:22.088684', '2022-04-28 12:10:22.088710', 0, 1, 3, 3, 'drf入门3', 'drf入门1drf入门1drf入门1drf入门1drf入门1drf入门1', '2022-04-28', 4);
INSERT INTO `luffy_course_chapter` VALUES (11, '2022-04-28 12:10:33.564141', '2022-04-28 12:10:33.564177', 0, 1, 4, 4, 'drf入门4', 'drf入门1drf入门1drf入门1drf入门1', '2022-04-28', 4);
INSERT INTO `luffy_course_chapter` VALUES (12, '2022-04-28 12:10:43.242918', '2022-04-28 12:10:43.242947', 0, 1, 5, 5, 'drf入门5', 'drf入门1drf入门1drf入门1drf入门1', '2022-04-28', 4);
INSERT INTO `luffy_course_chapter` VALUES (13, '2022-04-28 12:36:58.508995', '2022-04-28 12:36:58.509020', 0, 1, 1, 1, 'go第一章', 'go第一章', '2022-04-28', 5);
INSERT INTO `luffy_course_chapter` VALUES (14, '2022-04-28 12:37:08.588265', '2022-04-28 12:37:08.588287', 0, 1, 2, 2, 'go第二章', 'go第一章go第一章go第一章', '2022-04-28', 5);
INSERT INTO `luffy_course_chapter` VALUES (15, '2022-04-28 12:37:19.219405', '2022-04-28 12:37:19.219426', 0, 1, 3, 3, 'go第三章', 'go第一章go第一章go第一章', '2022-04-28', 5);
INSERT INTO `luffy_course_chapter` VALUES (16, '2022-04-28 12:40:11.445750', '2022-04-28 12:40:11.445774', 0, 1, 1, 1, '微服务第一章', '微服务第一章', '2022-04-28', 6);
INSERT INTO `luffy_course_chapter` VALUES (17, '2022-04-28 12:40:22.811647', '2022-04-28 12:40:22.811670', 0, 1, 2, 2, '微服务第二章', '微服务第二章微服务第二章微服务第二章', '2022-04-28', 6);


INSERT INTO `luffy_course_section` VALUES (1, '2019-07-14 14:02:33.779098', '2019-07-14 14:02:33.779135', 0, 1, '计算机原理上', 1, 2, '', NULL, '2019-07-14 14:02:33.779193', 1, 1);
INSERT INTO `luffy_course_section` VALUES (2, '2019-07-14 14:02:56.657134', '2019-07-14 14:02:56.657173', 0, 1, '计算机原理下', 2, 2, NULL, NULL, '2019-07-14 14:02:56.657227', 1, 1);
INSERT INTO `luffy_course_section` VALUES (3, '2019-07-14 14:03:20.493324', '2019-07-14 14:03:52.329394', 0, 1, '环境搭建上', 1, 2, NULL, NULL, '2019-07-14 14:03:20.493420', 0, 2);
INSERT INTO `luffy_course_section` VALUES (4, '2019-07-14 14:03:36.472742', '2019-07-14 14:03:36.472779', 0, 1, '环境搭建下', 2, 2, NULL, NULL, '2019-07-14 14:03:36.472831', 0, 2);
INSERT INTO `luffy_course_section` VALUES (5, '2019-07-14 14:04:19.338153', '2019-07-14 14:04:19.338192', 0, 1, 'web项目的创建', 1, 2, NULL, NULL, '2019-07-14 14:04:19.338252', 1, 3);
INSERT INTO `luffy_course_section` VALUES (6, '2019-07-14 14:04:52.895855', '2019-07-14 14:04:52.895890', 0, 1, 'Linux的环境搭建', 1, 2, NULL, NULL, '2019-07-14 14:04:52.895942', 1, 4);
INSERT INTO `luffy_course_section` VALUES (7, '2022-04-28 12:12:01.304920', '2022-04-28 12:12:01.304994', 0, 1, '文件操作', 2, 2, NULL, NULL, '2022-04-28 12:12:01.305074', 0, 5);
INSERT INTO `luffy_course_section` VALUES (8, '2022-04-28 12:12:11.287759', '2022-04-28 12:12:11.287884', 0, 1, '软件操作', 2, 2, NULL, NULL, '2022-04-28 12:12:11.288079', 0, 5);
INSERT INTO `luffy_course_section` VALUES (9, '2022-04-28 12:12:26.326077', '2022-04-28 12:12:26.326112', 0, 1, '请求响应', 1, 2, NULL, NULL, '2022-04-28 12:12:26.326174', 0, 8);
INSERT INTO `luffy_course_section` VALUES (10, '2022-04-28 12:12:36.364356', '2022-04-28 12:12:36.364391', 0, 1, '序列化类', 2, 2, NULL, NULL, '2022-04-28 12:12:36.364446', 0, 8);
INSERT INTO `luffy_course_section` VALUES (11, '2022-04-28 12:12:48.306119', '2022-04-28 12:12:48.306187', 0, 1, '三大认证', 1, 2, NULL, NULL, '2022-04-28 12:12:48.306396', 0, 9);
INSERT INTO `luffy_course_section` VALUES (12, '2022-04-28 12:13:06.882558', '2022-04-28 12:13:06.882620', 0, 1, '认证', 2, 2, NULL, NULL, '2022-04-28 12:13:06.882826', 0, 9);
INSERT INTO `luffy_course_section` VALUES (13, '2022-04-28 12:13:15.799043', '2022-04-28 12:13:15.799084', 0, 1, 'jwt认证', 1, 2, NULL, NULL, '2022-04-28 12:13:15.799146', 0, 10);
INSERT INTO `luffy_course_section` VALUES (14, '2022-04-28 12:13:27.852981', '2022-04-28 12:13:27.853011', 0, 1, 'jwt认证2', 3, 2, NULL, NULL, '2022-04-28 12:13:27.853066', 0, 10);
INSERT INTO `luffy_course_section` VALUES (15, '2022-04-28 12:13:37.292779', '2022-04-28 12:13:37.292806', 0, 1, '后台管理', 1, 2, NULL, NULL, '2022-04-28 12:13:37.292855', 0, 11);
INSERT INTO `luffy_course_section` VALUES (16, '2022-04-28 12:13:51.194585', '2022-04-28 12:13:51.194612', 0, 1, '后台管理2', 2, 2, NULL, NULL, '2022-04-28 12:13:51.194660', 0, 11);
INSERT INTO `luffy_course_section` VALUES (17, '2022-04-28 12:14:05.334836', '2022-04-28 12:14:05.334902', 0, 1, 'rbac1', 1, 2, NULL, NULL, '2022-04-28 12:14:05.335053', 0, 12);
INSERT INTO `luffy_course_section` VALUES (18, '2022-04-28 12:14:14.039605', '2022-04-28 12:14:14.039770', 0, 1, 'rbac2', 2, 2, NULL, NULL, '2022-04-28 12:14:14.039895', 0, 12);
INSERT INTO `luffy_course_section` VALUES (19, '2022-04-28 12:37:34.682049', '2022-04-28 12:37:34.682072', 0, 1, '环境搭建', 1, 2, NULL, NULL, '2022-04-28 12:37:34.682116', 0, 13);
INSERT INTO `luffy_course_section` VALUES (20, '2022-04-28 12:37:46.317414', '2022-04-28 12:37:46.317440', 0, 1, '第一个helloworld', 2, 2, NULL, NULL, '2022-04-28 12:37:46.317483', 0, 13);
INSERT INTO `luffy_course_section` VALUES (21, '2022-04-28 12:37:54.200236', '2022-04-28 12:37:54.200257', 0, 1, '变量定义', 1, 2, NULL, NULL, '2022-04-28 12:37:54.200297', 0, 14);
INSERT INTO `luffy_course_section` VALUES (22, '2022-04-28 12:38:03.465663', '2022-04-28 12:38:03.465686', 0, 1, '常量', 2, 2, NULL, NULL, '2022-04-28 12:38:03.465731', 0, 14);
INSERT INTO `luffy_course_section` VALUES (23, '2022-04-28 12:38:13.144613', '2022-04-28 12:38:13.144636', 0, 1, 'go结构体', 1, 2, NULL, NULL, '2022-04-28 12:38:13.144679', 0, 15);
INSERT INTO `luffy_course_section` VALUES (24, '2022-04-28 12:38:26.312273', '2022-04-28 12:38:26.312306', 0, 1, 'go接口', 2, 2, NULL, NULL, '2022-04-28 12:38:26.312380', 0, 15);
INSERT INTO `luffy_course_section` VALUES (25, '2022-04-28 12:40:36.531566', '2022-04-29 10:12:42.497098', 0, 1, '微服务第一章第一课时', 1, 2, NULL, NULL, '2022-04-28 12:40:36.531625', 1, 16);
INSERT INTO `luffy_course_section` VALUES (26, '2022-04-28 12:40:45.120568', '2022-04-28 12:41:14.341536', 0, 1, '微服务第一章第二课时', 2, 2, NULL, NULL, '2022-04-28 12:40:45.120627', 0, 16);
INSERT INTO `luffy_course_section` VALUES (27, '2022-04-28 12:40:57.477026', '2022-04-28 12:40:57.477048', 0, 1, '微服务第二章第一课时', 1, 2, NULL, NULL, '2022-04-28 12:40:57.477088', 0, 17);
INSERT INTO `luffy_course_section` VALUES (28, '2022-04-28 12:41:04.673613', '2022-04-28 12:41:04.673634', 0, 1, '微服务第二章第二课时', 2, 2, NULL, NULL, '2022-04-28 12:41:04.673673', 0, 17);


INSERT INTO `luffy_teacher` VALUES (1, '2019-07-14 13:44:19.661327', '2019-07-14 13:46:54.246271', 0, 1, 1, 'Alex', 1, '老男孩Python教学总监', '金角大王', 'teacher/alex_icon.png', '老男孩教育CTO & CO-FOUNDER 国内知名PYTHON语言推广者 51CTO学院20162017年度最受学员喜爱10大讲师之一 多款开源软件作者 曾任职公安部、飞信、中金公司、NOKIA中国研究院、华尔街英语、ADVENT、汽车之家等公司');
INSERT INTO `luffy_teacher` VALUES (2, '2019-07-14 13:45:25.092902', '2019-07-14 13:45:25.092936', 0, 1, 2, 'Mjj', 0, '前美团前端项目组架构师', NULL, 'teacher/mjj_icon.png', '是马JJ老师, 一个集美貌与才华于一身的男人,搞过几年IOS,又转了前端开发几年,曾就职于美团网任高级前端开发,后来因为不同意王兴(美团老板)的战略布局而出家做老师去了,有丰富的教学经验,开起车来也毫不含糊。一直专注在前端的前沿技术领域。同时,爱好抽烟、喝酒、烫头(锡纸烫)。 我的最爱是前端,因为前端妹子多。');
INSERT INTO `luffy_teacher` VALUES (3, '2019-07-14 13:46:21.997846', '2019-07-14 13:46:21.997880', 0, 1, 3, 'Lyy', 0, '老男孩Linux学科带头人', NULL, 'teacher/lyy_icon.png', 'Linux运维技术专家,老男孩Linux金牌讲师,讲课风趣幽默、深入浅出、声音洪亮到爆炸');


INSERT INTO `luffy_user` VALUES (1, 'pbkdf2_sha256$150000$GzSu8nqzDiqZ$KA2usjbMtAtvxlLyT0Cf7p840vMzlfUZ+y/QybAnCus=', '2022-04-28 11:39:51.807486', 1, 'lqz', '', '', '3@qq.com', 1, 1, '2022-04-20 12:14:34.013997', '18953675221', 'icon/default.png');
INSERT INTO `luffy_user` VALUES (2, 'pbkdf2_sha256$150000$xCV8p7UaVOBt$Em2kLIzI64GcL/7+l1jCzD4XFTPVddxT5BdjDmsNSQc=', NULL, 0, '15058066669', '', '', '', 0, 1, '2022-04-25 11:48:19.050064', '15058066669', 'icon/default.png');
INSERT INTO `luffy_user` VALUES (3, 'pbkdf2_sha256$150000$7NDocUXzFZSq$A43bx0o3ZrGabttb8NB7q32E0SBunncNIWH1pxMR+hI=', NULL, 0, '17673255100', '', '', '', 0, 1, '2022-04-25 11:51:49.918611', '17673255100', 'icon/default.png');
INSERT INTO `luffy_user` VALUES (4, 'pbkdf2_sha256$150000$4SFWTbi3c013$NuXd9kJuXWbvYChsS00NUfXCXAUTPonr7P7BNCxQ5wg=', NULL, 0, '13088229550', '', '', '', 0, 1, '2022-04-25 16:12:11.743720', '13088229550', 'icon/default.png');
INSERT INTO `luffy_user` VALUES (5, 'pbkdf2_sha256$150000$ftqIt2qLoVgJ$Gap4Bj5IhnwjnsknRQKcjPONKW4wbyZj3VGKbRI9iQ4=', NULL, 0, 'lqznb', '', '', '', 0, 1, '2022-04-27 12:32:20.458435', '12222222', 'icon/default.png');

下单接口

1.前端传入数据--->在订单表中插入记录,生成支付链接,返回给前端
	-前端传入数据:{'subject':'某个课程', 'total_amount':100, 'pay_type':1, 'courses':[1,2,3]}
    
2.后端做的事情--要保存,要校验--->序列化类来做
	1.订单总价校验
	2.生成订单号:唯一的
 	3.获取支付用户:request.user
	4.支付链接生成:支付宝支付链接
	5.入库(两个表)的信息准备

视图


from rest_framework.viewsets import GenericViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
class  PayOrderView(GenericViewSet):
    serializer_class = OlderSerializer
    authentication_classes = [JSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated]
    def create(self,requests,*args,**kwargs):

        ser = self.get_serializer(data = requests.data,context={"request":requests})
        ser.is_valid(raise_exception=True)
        ser.save()
        pay_url = ser.context.get('pay_url')
        return APIResponse(pay_url=pay_url)

序列化类

from rest_framework import serializers
from .models import Order,OrderDetail
from course.models import Course
from rest_framework.exceptions import APIException
import uuid
from libs.alipay_common import alipay,gateway

class OlderSerializer(serializers.ModelSerializer):
    # 高级用法 传入的courses=[1,2,3]---->courses=[id为1的课程对象,id为2的课程对象,id为3的课程对象]
    courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(),many=True)
    class Meta:
        model =Order
        fields = ['subject','total_amount','pay_type','courses']
    def _check_price(self,attrs):
        total_amount= attrs.get('total_amount')
        courses = attrs.get('courses')
        real_amount=0
        for course in courses:
            real_amount += course.price
        if not real_amount == total_amount:
            raise APIException('价格不对哦')

    def _product_num(self):
        return  str(uuid.uuid4())

    def _get_user(self):
        requsts = self.context.get('request')
        user= requsts.user
        return user

    def _get_url_path(self,attrs,out_trade_no):

        subject = attrs.get('subject')
        total_amount=attrs.get('total_amount')
        # 电脑网站支付,需要跳转到:https://openapi.alipay.com/gateway.do? + order_string
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=out_trade_no,
            total_amount=float(total_amount),
            subject=subject,
            return_url="https://example.com",
            notify_url="https://example.com/notify"  # 可选,不填则使用默认 notify url
        )
        print(order_string)
        pay_url = gateway + order_string
        print(pay_url)
        return pay_url


    def validate(self, attrs):
        # 1.检验价格对不对
        self._check_price(attrs)
        # 2.Order数据:subject,total_amount,out_trade_no,pay_type,user
        # 2.1 生成订单号:唯一的
        out_trade_no= self._product_num()
        # 2.2  获取user
        user = self._get_user()
        # 2.3 支付链接生成:支付宝支付链接
        pay_url=self._get_url_path(attrs,out_trade_no)
        self.context['pay_url'] = pay_url
        # 3.入库前准备
        attrs['out_trade_no']=out_trade_no
        attrs['user']=user
        print(attrs)
        return  attrs

    def create(self, validated_data):
        print(validated_data)
        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 validated_data

路由

from django.urls import path
from .views import AliPyaView,PayOrderView
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('pay',PayOrderView,'pay')
urlpatterns = [
    path('test/', AliPyaView.as_view()),
]
urlpatterns +=router.urls
posted @ 2023-07-04 21:30  DRAMA-娜娜  阅读(77)  评论(1)    收藏  举报