luffy课程表的创建-支付宝API-购买服务器
课程组件
<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">筛 选:</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-购买服务器的更多相关文章
- 支付宝api教程,支付宝根据交易号自动充值
最近公司要用php做一个网站支付宝自动充值的功能,具体就是客户把钱直接转到公司的支付宝账号里,然后在我们网站上填写上交易号,我们网站程序自动获取交易信息,自动给网站的账户充值. 我的具体想法就是利用支 ...
- 创建以 API 为中心的 Web 应用
http://www.oschina.net/translate/creating-an-api-centric-web-application?from=20130818 正计划着要开始搞一个新的网 ...
- 使用 ASP.NET Core MVC 创建 Web API(五)
使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...
- 使用 ASP.NET Core MVC 创建 Web API(四)
使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...
- Macbook pro从购买服务器到搭建服务器环境(1)
查看进程命令:ps -ef |grep *** ps -ef | grep nginx ps -ef | grep mysql ps -ef | grep mongops -ef | grep uws ...
- 【转】asp.net Core 系列【二】—— 使用 ASP.NET Core 和 VS2017 for Windows 创建 Web API
在本教程中,将生成用于管理“待办事项”列表的 Web API. 不会生成 UI. 概述 以下是将创建的 API: API 描述 请求正文 响应正文 GET /api/todo 获取所有待办事项 无 待 ...
- 【C#】使用OWIN创建Web API
OWIN的介绍 OWIN 的全称是 "Open Web Interface for .NET", OWIN 在 .NET Web 服务器和 .NET Web 应用之间定义了一套标准 ...
- 创建以API为中心的Web应用(转)
英文原文:Creating an API-Centric Web Application 引言 API——API是Application Programming Interface(应用编程接口)的简 ...
- 使用 ASP.NET Core MVC 创建 Web API——响应数据的内容协商(七)
使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 使 ...
随机推荐
- you-get加ffmpeg获取视频素材并转格式
最近做视频,觉得素材不好下载,下载了转格式又很麻烦,终于,在网上ob了很久的我找到了属于自己的工具. you-get视频下载 当你在网上找视频素材的时候发现了一个自己觉得很有意思的视频,但是获取这个视 ...
- JavaScript的函数和对象介绍
一.JavaScript中的函数 1.函数的概述 JavaScript中的函数是一段可执行代码的合集,在需要执行的时候可以在方法名之后添加一对小括号执行方法.是一段可执行的字符串. 2.函数中隐藏的属 ...
- 再战希捷:西部数据透露96层闪存已用于消费级SSD
导读 96层堆叠3D NAND闪存已经成为行业主流,包括西部数据这样的传统机械硬盘大厂,也在逐步普及96层闪存,并已经用于消费级SSD. 96层堆叠3D NAND闪存已经成为行业主流,包括西部数据这样 ...
- cmake的find_package()简单总结
遇到的问题 find_package(lzb)出现错误如下: CMake Warning at CMakeLists.txt:37 (find_package): By not providing & ...
- <强化学习>基本概念
马尔可夫决策过程MDP,是强化学习的基础. MDP --- <S,A,P,R,γ> AGENT STATE ENV REWARD ,由ENV给出.agent处于状态s下,采取acti ...
- python的常用序列
list1.list(obj)函数 obj可以为:元组(1,2,3),可迭代对象,字符串等转换换成数组类型2. 列表元素的添加 (1)list+[添加的元素] (2)list.append(添加元素) ...
- Java平台上的AOP实现机制
Java平台上的AOP实现机制 动态代理(Dynamic Proxy)机制,在运行期间动态的为相应接口生成对应的代理对象.SpringAop默认情况下采用这种机制来实现AOP机能.缺点:相对于编译后的 ...
- Codeforces 405E DFS
这个题目要求把一个无向连通图里面的所有边,分成 两个一对,只能出现一次,而且一对边必须是连在一起的,点可以复用 但边不可复用 可解条件很易得,因为图是连通的,只要边数为偶数即可. 一开始我借着做欧拉 ...
- POJ_3122 经典二分题
Pie Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8594 Accepted: 3124 Special Jud ...
- 低JAVA版本,高兼容性启动
低JAVA版本,高兼容性启动 背景:部分操作系统java环境低版本,暂时无法更新最新版本,新系统需要使用较高版本Java环境 1.JAVA低版本不兼容当前应用 2.解压安装JAVA,无需配置环境变量 ...