课程组件

<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. APIO 2010 特别行动队 斜率优化DP

    Description 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动队中队员的编号 应该连续,即为形如 (i ...

  2. python-arp 被动信息收集

    python-arp 被动信息收集 概述 横向移动的时候由于局域网中可能存在未分配的IP,如果请求这些未分配的IP可能导致被发现(旁路检测设备),先可以做一下arp被动信息收集.当然对蜜罐类设备没用. ...

  3. 【剑指Offer】面试题04. 二维数组中的查找

    题目 在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 示例: 现 ...

  4. NIO前奏之Path、Files、AsynchronousFileChannel

    NIO前奏之Path.Files.AsynchronousFileChannel   Java 1.4加入了nio包,Java 1.7 加入了真正的AIO(异步IO),AsynchronousFile ...

  5. DuplicateHandle伪句柄与实句柄的应用二

    //扫描进程列表,获得进程名为 ConsoleApplication2.exe的进程句柄B,把当前进程A的伪 //句柄传递给B,在B进程中关闭它 #include "stdafx.h&quo ...

  6. PHP - 验证码制作加验证

    一,主页 index.php   <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  7. my97datepicker实现日期改变立刻触发函数

    <input type="text" class="Wdate" onclick="WdatePicker({onpicking:functio ...

  8. maven学习(三)-使用maven来创建项目

    转自https://www.cnblogs.com/xdp-gacl/p/4240930.html maven作为一个高度自动化构建工具,本身提供了构建项目的功能,下面就来体验一下使用maven构建项 ...

  9. quartz详解3:quartz数据库集群-锁机制

    http://blog.itpub.NET/11627468/viewspace-1764753/ 一.quartz数据库锁 其中,QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,其表结 ...

  10. 设置Apache(httpd)和Nginx 开机自启动

     方法1: 进入目录: vi  /etc/rc.d/rc.local #设置apache 和 nginx 开机自启动/usr/sbin/apachectl start/usr/sbin/nginx s ...