课程组件

<template>
<div class="course">
<Header></Header>
<div class="main">
<!-- 筛选条件 -->
<div class="condition">
<ul class="cate-list">
<li class="title">课程分类:</li>
<li class="this">全部</li>
<li>Python</li>
<li>Linux运维</li>
<li>Python进阶</li>
<li>开发工具</li>
<li>Go语言</li>
<li>机器学习</li>
<li>技术生涯</li>
</ul> <div class="ordering">
<ul>
<li class="title">筛&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;选:</li>
<li class="default this">默认</li>
<li class="hot this">人气</li>
<li class="price this">价格</li>
</ul>
<p class="condition-result">共21个课程</p>
</div> </div>
<!-- 课程列表 -->
<div class="course-list">
<div class="course-item">
<div class="course-image">
<img src="@/assets/img/course-cover.jpeg" alt="">
</div>
<div class="course-info">
<h3>
<router-link to="/course/detail/1">Python开发21天入门</router-link>
<span><img src="@/assets/img/avatar1.svg" alt="">100人已加入学习</span></h3>
<p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
<ul class="lesson-list">
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span>
</li>
</ul>
<div class="pay-box">
<span class="discount-type">限时免费</span>
<span class="discount-price">¥0.00元</span>
<span class="original-price">原价:9.00元</span>
<span class="buy-now">立即购买</span>
</div>
</div>
</div>
<div class="course-item">
<div class="course-image">
<img src="@/assets/img/course-cover.jpeg" alt="">
</div>
<div class="course-info">
<h3>Python开发21天入门 <span><img src="@/assets/img/avatar1.svg" alt="">100人已加入学习</span></h3>
<p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
<ul class="lesson-list">
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span>
</li>
</ul>
<div class="pay-box">
<span class="discount-type">限时免费</span>
<span class="discount-price">¥0.00元</span>
<span class="original-price">原价:9.00元</span>
<span class="buy-now">立即购买</span>
</div>
</div>
</div>
<div class="course-item">
<div class="course-image">
<img src="@/assets/img/course-cover.jpeg" alt="">
</div>
<div class="course-info">
<h3>Python开发21天入门 <span><img src="@/assets/img/avatar1.svg" alt="">100人已加入学习</span></h3>
<p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
<ul class="lesson-list">
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span>
</li>
</ul>
<div class="pay-box">
<span class="discount-type">限时免费</span>
<span class="discount-price">¥0.00元</span>
<span class="original-price">原价:9.00元</span>
<span class="buy-now">立即购买</span>
</div>
</div>
</div>
<div class="course-item">
<div class="course-image">
<img src="@/assets/img/course-cover.jpeg" alt="">
</div>
<div class="course-info">
<h3>Python开发21天入门 <span><img src="@/assets/img/avatar1.svg" alt="">100人已加入学习</span></h3>
<p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
<ul class="lesson-list">
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
<li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span>
</li>
</ul>
<div class="pay-box">
<span class="discount-type">限时免费</span>
<span class="discount-price">¥0.00元</span>
<span class="original-price">原价:9.00元</span>
<span class="buy-now">立即购买</span>
</div>
</div>
</div>
</div>
</div>
<Footer></Footer>
</div>
</template> <script>
import Header from "@/components/Header"
import Footer from "@/components/Footer" export default {
name: "Course",
data() {
return {
category: 0,
}
},
components: {
Header,
Footer,
}
}
</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 .course-item:hover {
box-shadow: 4px 6px 16px rgba(0, 0, 0, .5);
} .course .course-item {
width: 1050px;
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 {
width: 100%;
} .course .course-item .course-info {
float: left;
width: 596px;
} .course-item .course-info h3 {
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 .lesson-list::after {
content: "";
display: block;
clear: both;
} .course-item .lesson-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 .lesson-list li .lesson-title {
/* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: inline-block;
max-width: 200px;
} .course-item .lesson-list li:hover {
background-image: url("/src/assets/img/play-icon-yellow.svg");
color: #ffc210;
} .course-item .lesson-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 .lesson-list li:hover .free {
color: #ffc210;
border-color: #ffc210;
} .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;
} .course-item .pay-box .buy-now:hover {
color: #fff;
background: #ffc210;
border: 1px solid #ffc210;
}
</style>

支付宝支付

支付流程分析:

开发者使用注意事项

  支付宝接口API官网:

创建应用,使用沙箱环境模拟开发应用

具体流程:

# 1、在沙箱环境下实名认证:https://openhome.alipay.com/platform/appDaily.htm?tab=info

# 2、电脑网站支付API:https://docs.open.alipay.com/270/105898/

# 3、完成RSA密钥生成:https://docs.open.alipay.com/291/105971

# 4、在开发中心的沙箱应用下设置应用公钥:填入生成的公钥文件中的内容

# 5、Python支付宝开源框架:https://github.com/fzlee/alipay
# >: pip install python-alipay-sdk --upgrade # 7、公钥私钥设置
"""
# alipay_public_key.pem
-----BEGIN PUBLIC KEY-----
支付宝公钥
-----END PUBLIC KEY----- # app_private_key.pem
-----BEGIN RSA PRIVATE KEY-----
用户私钥
-----END RSA PRIVATE KEY-----
""" # 8、支付宝链接
"""
开发:https://openapi.alipay.com/gateway.do
沙箱:https://openapi.alipaydev.com/gateway.do
"""

支付宝官方未提供相关的python的开发文档,在GitHub上查找开源的文档。

查看文档指南:

安装:

# installation
pip install python-alipay-sdk --upgrade

证书生成

# OpenSSL的
OpenSSL的 > genrsa -out app_private_key.pem 2048 #私钥文件
的OpenSSL > RSA -in app_private_key.pem -pubout退房手续app_public_key.pem#出口公钥
的OpenSSL > 退出

我们从open.alipay.com下载的公钥是一个字符串,此lib无法直接识别该字符串,请确保它被-----BEGIN PUBLIC KEY-----和包围。-----END PUBLIC KEY-----

初始化

从支付宝进口 AliPay,ISVAliPay

#确保您的密钥文件符合标准。
#您可以在tests / certs / ali / ali_private_key.pem中找到示例
app_private_key_string = open( “ /path/to/your/private/key.pem ”).read()
alipay_public_key_string = 打开(“ /path/to/alipay/public/key.pem ”).read() app_private_key_string = “”“
----- BEGIN RSA PRIVATE KEY -----
base64编码的内容
----- END RSA PRIVATE KEY -----
”“” alipay_public_key_string = “”“
----- BEGIN PUBLIC KEY -----
base64编码的内容
----- END PUBLIC KEY -----
”“” 支付宝=支付宝(
的appid = “ ”,
app_notify_url = 无, #默认的通知路径
app_private_key_string = app_private_key_string,
#支付宝的公共密钥,不要用你自己的公钥!
alipay_public_key_string = alipay_public_key_string,
sign_type = “ RSA ”,# RSA或RSA2
调试= False #默认为False
) #忘掉我下面提到的,如果你不知道什么是ISV
#要么app_auth_code或app_auth_token不应该是无
isv_alipay = ISVAliPay(
的appid = “ ”,
app_notify_url = 无, #默认的通知路径
app_private_key_string = “ ”,
#支付宝公钥,不要用你自己的公钥!
alipay_public_key_string = alipay_public_key_string,
sign_type = “ RSA ” # RSA或RSA2
调试= False #默认
为False ,app_auth_code = None,
app_auth_token = None

命名约定

给定支付宝功能,例如alipay.trade.page.pay,我们将定义一个相应的功能alipay.api_alipay_trade_page_pay()

通常我们会进行这样的翻译:

function_name = "api_" + alipay_function_name.replace(".", "_")
根据支付宝文件,输入的某些参数biz_content是可选的,而有些则不是。我们以这种方式定义函数,以便您可以将这些可选参数放入kwargs: def api_alipay_xxx(self, out_trade, total_amount, **kwargs):
...
biz_content.update(kwargs)

alipay.trade.page.pay

#对于Python 2用户(您应该真正考虑Python 3),
#确保非ascii字符串是utf-8编码的
subject = u “测试订单” .encode( “ utf8 ”)
#对于Python 3用户,只需使用默认字符串
主题 = “测试订单” #通过网络付款,在浏览器中打开以下URL:https://openapi.alipay.com/gateway.do?+ order_string
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no = “ 20161112 ”,
TOTAL_AMOUNT = 0.01,
受试者=受试者
return_url = “ https://example.com ”,
notify_url = “ https://example.com/notify ” #这是可选

支付宝付款

#通过WAP付款,在浏览器中打开以下网址:https://openapi.alipay.com/gateway.do?+ order_string
order_string = alipay.api_alipay_trade_wap_pay(
out_trade_no = “ 20161112 ”,
TOTAL_AMOUNT = 0.01,
受试者=受试者
return_url = “ http://example.com ”,
notify_url = “ https://example.com/notify ” #这是可选

开发环境初步测试使用

  结合沙箱提供的ID和公钥秘钥:

# pip install python-alipay-sdk

from alipay import AliPay

# 应用私钥
app_private_key_string = """-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAwwVRL+w7diqoML52m7WA382fhnyBFppI9ZR5eO1WvS9x52uBRxBX0cM0MfuKsRxMqWGMqZubGgmxNF3wsyyDNtGYBZsgAIitIHadyqyNkAeSj52hVLtmGTrFH5rW3GFma2XGaLuDxBOHuP8dCmhIY5v85Ugm1LmBGmZyI5ZiuZChc5JEqAJzBFZp8TgOiwzLdGkCY1fZPi7YKndt4Mte81FxDAiFIGI7kfO2s8PVsX1z44SlD4e1dvRcKFwh/C6cbEYtZGV5VGRNxSq+ELr4bVD9wlwTl2jxGyAPMGP/sXmc0vV1XmSHB9L1NKgQKeOHNImjOI6P668BcxvrSGeQgwIDAQABAoIBADkXq2buL5IudsKeX7bB8hKS7eq/NENbs5RBfTZLtSL5as0nCde2Dx+XmAYx765d7IuBxV458bQzti7weXDazScVQP4TJdFCMfzY/OTCk0bhEKT+rqZRnlgwflj8SX6G/SbfyrAKhU63sPoVpXjQgrC2j9jHwKZyEDucVjnY4toT3HZagV92LIKjOOU64fDL53AnO22lLE2r4SH1rDYE1vo6aGIvRQTeUM+ayVHyxIxj6rLlPYWJ4iWujjiO4H1ENyUhiK2haccXNpLTHpriitQPNNBA0GgI0sEj0hK0dm/M4f2yC5QkIUM89ZJpTZ+j1jc40DmziSjYHYRUyoVd1SECgYEA49Awp1t6WV3ZmYQ+Wd7SI5XllddyK5STm9ZhFnQj87ABESSlbWBujmitSMj+c6GIRsrMNxsoiVIRoY8yHDrluJCyCtJjJuzWu4pn4gBjAhMIe35jDWfz8EsEbp0QktUAmJnUCQCCbYT4LmViRodDSI43XOy8pU6hP3dm46emN+kCgYEA2yZzXUeFTGxXkQpEMqK0SbhDYgU7IMZzn2qL1paCr4MFnl5AcCi6/9X+OyZ3esjwklU3+87AlLuZeg5vXaFpfrndccJc9LPqXQRTWI33cULMikdQQJcJQsE8b1v4wdpfpAnlSE+wqID7zZ9+JfToDxuKMHya/CQmCYypfXHxbYsCgYEA3gdtM98bOngWeOGDZ1GcWuRf8w8cjc7roglpbFnbJEjYcV3XAOfoOFFa+cIzBH1ddSl3qQmGE3fyCRSn0Q2yEJStgZCU5D4V9ogpQQIBfOcR8FI4tbsn630hn7Dik0iXoSLjnbZqZ9UdkRJsmrJ/5/n7iUyNe0tMKq/zjlM50+kCgYEAqnWeBlA7PtaGxipWIYys7yqEPxoSg8vY44bcfm1T+XDQTf7B4HvN+HFa7mddSAREG45tnU+UPBwvpODVft6uUAQCWxnzc+L9yJw0uAy1C0QKFQSjR5ozedkUSQog06gn/FA2J6jUoDyzn50PYja8ygOB2XUSmE0FySfALfMS90ECgYEA0vvySTF0b5tzgLAZLQfqwtJIcsc/MtXWv+xrm6LeIkxKMQAyxneynvyDlekJTh9Tgw3n87tGbYMCUmnxfnE7UKldqVc7jTfP2WL2OlMX0J344I6ABWHIpttwGrRrICcpd1G4J8kdT5ug+/ZtachnHBhmSOtbj6beGsG8X68tezc=
-----END RSA PRIVATE KEY-----""" # 支付宝公钥
alipay_public_key_string = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgCLK/MIs0gsKSk/DqzKwf7F9m8hyGqJM97af5IRkEdVCvFI5U1Y8xZsR8mWj+YhIU9rv48zZn81uJ7OqkkWXc/ENCMqGTiEe4tKPniLibTdpaIgPNn9c3QSa03psvJI8v/n5+0rs+KKXxN8UwLcmMMN5Zfy8Ejvq/rax9EXepxLqSP7xQ8DXHRBCkFHUY6W2vdIKQZFc8wqMqglRjGjfN8OgYwaN2F6TPPPHdoVbpjduEx1RlACItapHNWv21YTr0PYx+edb3Oj+Tjfinzuyb9S0uXDEHOOGeLrerOSJr3rVwDJpFKye6Lojz9H7aV+gki1Mp4W2qykyefYEmkDtYwIDAQAB
-----END PUBLIC KEY-----""" alipay = AliPay(
appid="",
app_notify_url=None, # 默认不用设置
app_private_key_string=app_private_key_string,
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_string=alipay_public_key_string,
sign_type="RSA2", # RSA 或者 RSA2
debug=True # 默认False
) import time
if __name__ == '__main__':
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=str(time.time()),
total_amount=6.66,
subject='小红帽',
return_url="http://127.0.0.1:8080",
notify_url="https://example.com/notify"
)
order_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
print(order_url) from libs.iPay import alipay, pay_url
import time
if __name__ == '__main__':
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=str(time.time()),
total_amount=6.66,
subject='小红帽',
return_url="http://127.0.0.1:8080",
notify_url="https://example.com/notify"
)
order_url = pay_url + order_string
print(order_url)

aliapy二次封装包

依赖
>: pip install python-alipay-sdk --upgrade
结构
libs
├── iPay # aliapy二次封装包
│ ├── __init__.py # 包文件
│ ├── keys # 密钥文件夹
│ │ ├── alipay_public_key.pem # 支付宝公钥
│ │ └── app_private_key.pem # 应用私钥
└── └── settings.py # 应用配置

settings.py

import os
# 支付宝应用id
APP_ID = ''
# 默认异步回调的地址,通常设置None就行
APP_NOTIFY_URL = None
# 应用私钥文件路径
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'
# 是否是测试环境 - 是否是支付宝沙箱
DEBUG = True
# 支付连接
DEV_PAY_URL = 'https://openapi.alipaydev.com/gateway.do?'
PROD_PAY_URL = 'https://openapi.alipay.com/gateway.do?'
__init__.py
from alipay import AliPay
from .settings import *
# 对外提供支付对象
alipay = AliPay(
appid=APP_ID,
app_notify_url=APP_NOTIFY_URL,
app_private_key_path=APP_PRIVATE_KEY_PATH,
alipay_public_key_path=ALIPAY_PUBLIC_KEY_PATH,
sign_type=SIGN_TYPE,
debug=DEBUG
) # 对外提供的支付链接前缀
pay_url = DEV_PAY_URL if DEBUG else PROD_PAY_URL
alipay_public_key.pem
-----BEGIN PUBLIC KEY-----
支付宝公钥
-----END PUBLIC KEY-----
app_private_key.pem
-----BEGIN RSA PRIVATE KEY-----
应用私钥
-----END RSA PRIVATE KEY-----
补充:dev.py
# 前后台base_url
UP_BASE_URL = 'http://127.0.0.1:8080'
END_BASE_URL = 'http://127.0.0.1:8000' # alipay回调接口配置
# 上线后必须换成官网地址
# 同步回调的接口(get),前后台分离时一般设置前台页面url
RETURN_URL = UP_BASE_URL + '/pay/success'
# 异步回调的接口(post),一定设置为后台服务器接口
NOTIFY_URL = END_BASE_URL + '/order/success/'

支付模块

order/models.py
from django.db import models

# 订单表:
from django.db import models
from utils.model import BaseModel
from user.models import User
from course.models import Course 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)
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="支付时间")
user = models.ForeignKey(User, related_name='user_orders', 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(BaseModel):
"""订单详情"""
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):
return "%s订单(%s)" % (self.course.name, self.order.out_trade_no)

后台接口

from django.urls import path
from . import views
urlpatterns = [
path('pay/', views.PayAPIView.as_view()),
path('success/', views.SuccessAPIView.as_view()),
]

订单序列化模块

from rest_framework import serializers
from . import models
class OrderModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Order
fields = ('subject', 'total_amount', 'out_trade_no', 'pay_type', 'user')
extra_kwargs = {
'pay_type': {
'required': True
},
'total_amount': {
'required': True
},
}

支付接口生成支付链接

import time
from rest_framework.views import APIView
from utils.response import APIResponse
from libs.iPay import alipay
from . import authentications, serializers
from rest_framework.permissions import IsAuthenticated
from django.conf import settings
# 获取前台 商品名、价格,产生 订单、支付链接
class PayAPIView(APIView):
authentication_classes = [authentications.JWTAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request, *args, **kwargs):
# 前台提供:商品名、总价、支付方式
request_data = request.data
# 后台产生:订单号、用户
out_trade_no = '%d' % time.time() * 2
request_data['out_trade_no'] = out_trade_no
request_data['user'] = request.user.id # 反序列化数据,用于订单生成前的校验
order_ser = serializers.OrderModelSerializer(data=request_data)
if order_ser.is_valid():
# 生成订单,订单默认状态为:未支付
order = order_ser.save()
# 支付链接的参数
order_string = alipay.api_alipay_trade_page_pay(
subject=order.subject,
out_trade_no=order.out_trade_no,
total_amount='%.2f' % order.total_amount,
return_url=settings.RETURN_URL,
notify_url=settings.NOTIFY_URL
)
# 形成支付链接:alipay._gateway根据字符环境DEBUG配置信息,决定是沙箱还是真实支付环境
pay_url = '%s?%s' % (alipay._gateway, order_string)
return APIResponse(0, 'ok', pay_url=pay_url) return APIResponse(1, 'no ok', results=order_ser.errors)

前台回调接口的页面

{
path: '/pay/success',
name: 'pay-success',
component: PaySuccess
},

前端接收数据渲染

<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>
<Footer/>
</div>
</template> <script>
import Header from "@/components/Header"
import Footer from "@/components/Footer" export default {
name: "Success",
data() {
return {
result: {},
};
},
created() {
// 判断登录状态
let token = this.$cookies.get('token');
if (!token) {
this.$message.error('非法请求');
this.$router.go(-1)
} localStorage.this_nav = '/';
if (!location.search.length) return;
let params = location.search.substring(1);
let items = params.length ? params.split('&') : [];
//逐个将每一项添加到args对象中
for (let i = 0; i < items.length; i++) {
let k_v = items[i].split('=');
//解码操作,因为查询字符串经过编码的
let k = decodeURIComponent(k_v[0]);
let v = decodeURIComponent(k_v[1]);
this.result[k] = v;
// this.result[k_v[0]] = k_v[1];
}
// console.log(this.result); // 把地址栏上面的支付结果,转发给后端
this.$axios({
url: this.$settings.base_url + '/order/success/' + location.search,
method: 'patch',
headers: {
Authorization: token
}
}).then(response => {
console.log(response.data);
}).catch(() => {
console.log('支付结果同步失败');
})
},
components: {
Header,
Footer,
}
}
</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>

支付完成订单校验的接口

from . import models
from utils.logging import logger
from rest_framework.response import Response
class SuccessAPIView(APIView):
# 不能认证,别人支付宝异步回调就进不来了
# authentication_classes = [authentications.JWTAuthentication]
# permission_classes = [IsAuthenticated]
def patch(self, request, *args, **kwargs):
# 默认是QueryDict类型,不能使用pop方法
request_data = request.query_params.dict()
# 必须将 sign、sign_type(内部有安全处理) 从数据中取出,拿sign与剩下的数据进行校验
sign = request_data.pop('sign')
result = alipay.verify(request_data, sign)
if result: # 同步回调:修改订单状态
try:
out_trade_no = request_data.get('out_trade_no')
order = models.Order.objects.get(out_trade_no=out_trade_no)
if order.order_status != 1:
order.order_status = 1
order.save()
except:
pass
return APIResponse(0, '支付成功')
return APIResponse(1, '支付失败') # 支付宝异步回调
def post(self, request, *args, **kwargs):
# 默认是QueryDict类型,不能使用pop方法
request_data = request.data.dict()
# 必须将 sign、sign_type(内部有安全处理) 从数据中取出,拿sign与剩下的数据进行校验
sign = request_data.pop('sign')
result = alipay.verify(request_data, sign)
# 异步回调:修改订单状态
if result and request_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED" ):
out_trade_no = request_data.get('out_trade_no')
logger.critical('%s支付成功' % out_trade_no)
try:
order = models.Order.objects.get(out_trade_no=out_trade_no)
if order.order_status != 1:
order.order_status = 1
order.save()
except:
pass
# 支付宝八次异步通知,订单成功一定要返回 success
return Response('success')
return Response('failed')

luffy课程表的创建-支付宝API-购买服务器的更多相关文章

  1. 支付宝api教程,支付宝根据交易号自动充值

    最近公司要用php做一个网站支付宝自动充值的功能,具体就是客户把钱直接转到公司的支付宝账号里,然后在我们网站上填写上交易号,我们网站程序自动获取交易信息,自动给网站的账户充值. 我的具体想法就是利用支 ...

  2. 创建以 API 为中心的 Web 应用

    http://www.oschina.net/translate/creating-an-api-centric-web-application?from=20130818 正计划着要开始搞一个新的网 ...

  3. 使用 ASP.NET Core MVC 创建 Web API(五)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

  4. 使用 ASP.NET Core MVC 创建 Web API(四)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

  5. Macbook pro从购买服务器到搭建服务器环境(1)

    查看进程命令:ps -ef |grep *** ps -ef | grep nginx ps -ef | grep mysql ps -ef | grep mongops -ef | grep uws ...

  6. 【转】asp.net Core 系列【二】—— 使用 ASP.NET Core 和 VS2017 for Windows 创建 Web API

    在本教程中,将生成用于管理“待办事项”列表的 Web API. 不会生成 UI. 概述 以下是将创建的 API: API 描述 请求正文 响应正文 GET /api/todo 获取所有待办事项 无 待 ...

  7. 【C#】使用OWIN创建Web API

    OWIN的介绍 OWIN 的全称是 "Open Web Interface for .NET", OWIN 在 .NET Web 服务器和 .NET Web 应用之间定义了一套标准 ...

  8. 创建以API为中心的Web应用(转)

    英文原文:Creating an API-Centric Web Application 引言 API——API是Application Programming Interface(应用编程接口)的简 ...

  9. 使用 ASP.NET Core MVC 创建 Web API——响应数据的内容协商(七)

    使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...

随机推荐

  1. you-get加ffmpeg获取视频素材并转格式

    最近做视频,觉得素材不好下载,下载了转格式又很麻烦,终于,在网上ob了很久的我找到了属于自己的工具. you-get视频下载 当你在网上找视频素材的时候发现了一个自己觉得很有意思的视频,但是获取这个视 ...

  2. JavaScript的函数和对象介绍

    一.JavaScript中的函数 1.函数的概述 JavaScript中的函数是一段可执行代码的合集,在需要执行的时候可以在方法名之后添加一对小括号执行方法.是一段可执行的字符串. 2.函数中隐藏的属 ...

  3. 再战希捷:西部数据透露96层闪存已用于消费级SSD

    导读 96层堆叠3D NAND闪存已经成为行业主流,包括西部数据这样的传统机械硬盘大厂,也在逐步普及96层闪存,并已经用于消费级SSD. 96层堆叠3D NAND闪存已经成为行业主流,包括西部数据这样 ...

  4. cmake的find_package()简单总结

    遇到的问题 find_package(lzb)出现错误如下: CMake Warning at CMakeLists.txt:37 (find_package): By not providing & ...

  5. <强化学习>基本概念

    马尔可夫决策过程MDP,是强化学习的基础. MDP --- <S,A,P,R,γ> AGENT STATE ENV  REWARD   ,由ENV给出.agent处于状态s下,采取acti ...

  6. python的常用序列

    list1.list(obj)函数 obj可以为:元组(1,2,3),可迭代对象,字符串等转换换成数组类型2. 列表元素的添加 (1)list+[添加的元素] (2)list.append(添加元素) ...

  7. Java平台上的AOP实现机制

    Java平台上的AOP实现机制 动态代理(Dynamic Proxy)机制,在运行期间动态的为相应接口生成对应的代理对象.SpringAop默认情况下采用这种机制来实现AOP机能.缺点:相对于编译后的 ...

  8. Codeforces 405E DFS

    这个题目要求把一个无向连通图里面的所有边,分成 两个一对,只能出现一次,而且一对边必须是连在一起的,点可以复用  但边不可复用 可解条件很易得,因为图是连通的,只要边数为偶数即可. 一开始我借着做欧拉 ...

  9. POJ_3122 经典二分题

    Pie Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8594   Accepted: 3124   Special Jud ...

  10. 低JAVA版本,高兼容性启动

    低JAVA版本,高兼容性启动 背景:部分操作系统java环境低版本,暂时无法更新最新版本,新系统需要使用较高版本Java环境 1.JAVA低版本不兼容当前应用 2.解压安装JAVA,无需配置环境变量 ...