文章目录
- 13-订单生成
- 03_提交订单页面显示
- 04_创建订单前端js
- 01_订单生成_mysql事务概念
- 02_订单生成_django中使用事务
- 14-订单并发处理
- 02_订单并发_悲观锁
- 03_订单并发_乐观锁
- 并发处理总结
- 区别
- 应用场景
- 事务的隔离性
- 修改隔离性
- 15-订单支付、评论
- 用户中心-订单页面
- 订单支付_获取支付结果
- 支付流程
- 配置支付宝支付接口
- openssl操作
- 沙箱环境
- 设置沙箱买家 购买
- 前后台代码逻辑
- 获取支付结果
- 订单评论
- 评论 order_comment.html
- 评论后端逻辑
- 评论后商品详情
13-订单生成
03_提交订单页面显示
class OrderPlaceView(LoginRequiredMixin, View):
"""订单提交页面"""
def post(self, request):
user = request.user
# 获取提交的商品ids
sku_ids = request.POST.getList('sku_ids')
# 验证sku_ids
if not sku_ids:
return redirect(reverse('cart:show'))
conn = get_redis_connection('default')
cart_key = 'cart_%s' % user.id
skus = []
total_count = 0
total_price = 0
for sku_id in sku_ids:
# 获取商品的信息和数量
sku = GoodsSKU.objects.get(id=sku_id)
count = conn.hget(cart_key, sku_id)
amount = sku.price * int(count)
# 动态添加数量和小计
sku.count = count
sku.amount = amount
skus.append(sku)
total_price += amount
total_count += int(count)
# 写死运费
transit_price = 10
# 实付款
total_pay = total_price + transit_price
# 获取用户收件地址
addrs = Address.objects.filter(user=user)
sku_ids = ''.join(sku_ids)
# 组织上下文
context = {
'skus': skus,
'total_count': total_count,
'total_price': total_price,
'transit_price': transit_price,
'total_pay': total_pay,
'addrs': addrs,
'sku_ids': sku_ids,
}
return render(request, 'place_order.html', context)
04_创建订单前端js
{% block bottomfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script type="text/javascript">
$('#order_btn').click(function() {
// 获取用户选择的地址id, 支付方式, 要购买的商品id字符串
addr_id = $('input[name="addr_id"]:checked').val()
pay_method = $('input[name="pay_style"]:checked').val()
sku_ids = $(this).attr('sku_ids')
csrf = $('input[name="csrfmiddlewaretoken"]').val()
// alert(addr_id+":"+pay_method+':'+sku_ids)
// 组织参数
params = {'addr_id':addr_id, 'pay_method':pay_method, 'sku_ids':sku_ids,
'csrfmiddlewaretoken':csrf}
// 发起ajax post请求,访问/order/commit, 传递的参数: addr_id pay_method, sku_ids
$.post('/order/commit', params, function (data) {
if (data.res == 5){
// 创建成功
localStorage.setItem('order_finish',2);
$('.popup_con').fadeIn('fast', function() {
setTimeout(function(){
$('.popup_con').fadeOut('fast',function(){
window.location.href = '/user/order/1';
});
},3000)
});
}
else{
alert(data.errmsg)
}
})
});
</script>
{% endblock bottomfiles %}
01_订单生成_mysql事务概念
02_订单生成_django中使用事务
from django.db import transaction
# 设置事务保存点
save_id = transaction.savepoint()
try:
# 向df_order_info表中添加一条记录
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
total_count=total_count,
total_price=total_price,
transit_price=transit_price)
# 用户的订单中有几个商品,需要向df_order_goods表中加入几条记录
conn = get_redis_connection('default')
cart_key = 'cart_%d' % user.id
# sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
# 获取商品的信息
try:
# select * from df_goods_sku where id=sku_id for update;
# 在查询的时候就进行加锁,其他进程需要等待该进行commit或者rollback之后才释放锁
"""
悲观锁就是在查询的时候就进行枷锁
乐观锁不在查询的时候加锁,而是在判断更新库存的时候和之前查到的库存是不是相等
不相等的话说明其间别人把库存进行了修改
"""
print(sku_id)
sku = GoodsSKU.objects.get(id=sku_id) # .select_for_update()
except:
# 商品不存在
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 4, 'errmsg': '商品不存在'})
# 从redis中获取用户所要购买的商品的数量
count = conn.hget(cart_key, sku_id)
# 判断商品的库存
if int(count) > sku.stock:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 6, 'errmsg': '商品库存不足'})
# 向df_order_goods表中添加一条记录
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price)
# 更新商品的库存和销量
sku.stock -= int(count)
sku.sales += int(count)
sku.save()
# 累加计算订单商品的总数量和总价格
amount = sku.price * int(count)
total_count += int(count)
total_price += amount
# 更新订单信息表中的商品的总数量和总价格
order.total_count = total_count
order.total_price = total_price
order.save()
except Exception as e:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 7, 'errmsg': '下单失败'})
# 提交事务,否则不会提交
transaction.savepoint_commit(save_id)
14-订单并发处理
02_订单并发_悲观锁
当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制
但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会。另外还会降低并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
class OrderCommitView(View):
"""订单提交:悲观锁"""
@transaction.atomic
def post(self, request):
# 验证用户
user = request.user
if not user.is_authenticated:
return JsonResponse({'res': 0, 'errmsg': '用户未登录'})
# 接受参数
addr_id = request.POST.get('addr_id')
pay_method = request.POST.get('pay_method')
sku_ids = request.POST.get('sku_ids')
# 验证参数
if not all([addr_id, pay_method, sku_ids]):
return JsonResponse({'res': 1, 'errmsg': '参数不完整'})
if pay_method not in OrderInfo.PAY_METHODS.keys():
return JsonResponse({'res': 2, 'errmsg': '非法支付方式'})
try:
addr = Address.objects.get(id=addr_id)
except Address.DoesNotExist as e:
return JsonResponse({'res': 3, 'errmsg': '地址不存在'})
# 创建订单核心业务
# 创建订单核心业务
# 组织参数
# 订单id: 20171122181630+用户id
order_id = datetime.now().strftime('%Y%m%d%H%M%S') + str(user.id)
# 运费
transit_price = 10
# 总数目和总金额
total_count = 0
total_price = 0
# 设置事务保存点
save_id = transaction.savepoint()
try:
# 向df_order_info表中添加一条记录
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
total_count=total_count,
total_price=total_price,
transit_price=transit_price)
# 用户的订单中有几个商品,需要向df_order_goods表中加入几条记录
conn = get_redis_connection('default')
cart_key = 'cart_%d' % user.id
# sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
# 获取商品的信息
try:
# select * from df_goods_sku where id=sku_id for update;
# 在查询的时候就进行加锁,其他进程需要等待该进行commit或者rollback之后才释放锁
"""
悲观锁就是在查询的时候就进行枷锁
乐观锁不在查询的时候加锁,而是在判断更新库存的时候和之前查到的库存是不是相等
不相等的话说明其间别人把库存进行了修改
"""
sku = GoodsSKU.objects.select_for_update().get(id=sku_id) # .select_for_update()
except:
# 商品不存在
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 4, 'errmsg': '商品不存在'})
# print(user.id ,sku.stock)
# 从redis中获取用户所要购买的商品的数量
count = conn.hget(cart_key, sku_id)
# 判断商品的库存
if int(count) > sku.stock:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 6, 'errmsg': '商品库存不足'})
# 向df_order_goods表中添加一条记录
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price)
# 更新商品的库存和销量
sku.stock -= int(count)
sku.sales += int(count)
sku.save()
# 累加计算订单商品的总数量和总价格
amount = sku.price * int(count)
total_count += int(count)
total_price += amount
# 更新订单信息表中的商品的总数量和总价格
order.total_count = total_count
order.total_price = total_price
order.save()
except Exception as e:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 7, 'errmsg': '下单失败'})
# 提交事务,否则不会提交
transaction.savepoint_commit(save_id)
# 清除用户购物车中对应的记录
conn.hdel(cart_key, *sku_ids)
# 返回应答
return JsonResponse({'res': 5, 'message': '创建成功'})
03_订单并发_乐观锁
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做
乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。
尝试三次判断,查看更新后数据是否保持一致
class OrderCommitView1(View):
"""
订单提交:乐观锁
需要在mysql的配置文件中添加mysql的事务隔离级别为read-commited只读提交的内容
防止读取不到另一个事务提交后的更新数据
"""
@transaction.atomic
def post(self, request):
# 验证用户
user = request.user
if not user.is_authenticated():
return JsonResponse({'res': 0, 'errmsg': '用户未登录'})
# 接受参数
addr_id = request.POST.get('addr_id')
pay_method = request.POST.get('pay_method')
sku_ids = request.POST.get('sku_ids')
# 验证参数
if not all([addr_id, pay_method, sku_ids]):
return JsonResponse({'res': 1, 'errmsg': '参数不完整'})
if pay_method not in OrderInfo.PAY_METHODS.keys():
return JsonResponse({'res': 2, 'errmsg': '非法支付方式'})
try:
addr = Address.objects.get(id=addr_id)
except Address.DoesNotExist as e:
return JsonResponse({'res': 3, 'errmsg': '地址不存在'})
# 创建订单核心业务
# 创建订单核心业务
# 组织参数
# 订单id: 20171122181630+用户id
order_id = datetime.now().strftime('%Y%m%d%H%M%S') + str(user.id)
# 运费
transit_price = 10
# 总数目和总金额
total_count = 0
total_price = 0
# 设置事务保存点
save_id = transaction.savepoint()
try:
# 向df_order_info表中添加一条记录
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
total_count=total_count,
total_price=total_price,
transit_price=transit_price)
# 用户的订单中有几个商品,需要向df_order_goods表中加入几条记录
conn = get_redis_connection('default')
cart_key = 'cart_%d' % user.id
sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
# 获取商品的信息
for i in range(3):
try:
# select * from df_goods_sku where id=sku_id for update;
# 在查询的时候就进行加锁,其他进程需要等待该进行commit或者rollback之后才释放锁
"""
悲观锁就是在查询的时候就进行枷锁
乐观锁不在查询的时候加锁,而是在判断更新库存的时候和之前查到的库存是不是相等
不相等的话说明其间别人把库存进行了修改
"""
sku = GoodsSKU.objects.get(id=sku_id)
except:
# 商品不存在
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 4, 'errmsg': '商品不存在'})
print('user:%d stock:%d' % (user.id, sku.stock))
# 从redis中获取用户所要购买的商品的数量
count = conn.hget(cart_key, sku_id)
# 判断商品的库存
if int(count) > sku.stock:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 6, 'errmsg': '商品库存不足'})
# 更新商品的库存和销量
orgin_stock = sku.stock
new_stock = orgin_stock - int(count)
new_sales = sku.sales + int(count)
# 返回受影响的行数,表示1更新成功,返回0表示更新失败
res = GoodsSKU.objects.filter(id=sku_id, stock=orgin_stock) \
.update(stock=new_stock, sales=new_sales)
if res == 0:
if i == 2:
# 尝试到第3次
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 7, 'errmsg': '下单失败'})
else:
continue
# 向df_order_goods表中添加一条记录
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price)
# 累加计算订单商品的总数量和总价格
amount = sku.price * int(count)
total_count += int(count)
total_price += amount
# 若用户不到3此酒秒杀成功直接跳出循环
break
# 更新订单信息表中的商品的总数量和总价格
order.total_count = total_count
order.total_price = total_price
order.save()
except Exception as e:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res': 7, 'errmsg': '下单失败'})
# 提交事务,否则不会提交
transaction.savepoint_commit(save_id)
# 清除用户购物车中对应的记录
conn.hdel(cart_key, *sku_ids)
# 返回应答
return JsonResponse({'res': 5, 'message': '创建成功'})
并发处理总结
区别
悲观锁就是在查询的时候就进行枷锁
乐观锁不在查询的时候加锁,而是在判断更新库存的时候和之前查到的库存是不是相等,不相等的话说明其间别人把库存进行了修改
应用场景
在乐观锁与悲观锁的选择上面,主要看下两者的区别以及适用场景就可以了。
乐观锁并未真正加锁,效率高。一旦锁的粒度掌握不好,更新失败的概率就会比较高,容易发生业务失败。
悲观锁依赖数据库锁,效率低。更新失败的概率比较低。
随着互联网三高架构(高并发、高性能、高可用)的提出,悲观锁已经越来越少的被使用到生产环境中了,尤其是并发量比较大的业务场景。
事务的隔离性
修改隔离性
需要在mysql的配置文件中添加mysql的事务隔离级别为read-commited只读提交的内容
防止读取不到另一个事务提交后的更新数据
15-订单支付、评论
用户中心-订单页面
class UserOrderView(LoginRequiredMixin, View):
"""用户中心-订单页面"""
def get(self, request, page):
user = request.user
# 数据库获取用户的订单信息
orders = OrderInfo.objects.filter(user=user).order_by('-create_time')
for order in orders:
order_skus = OrderGoods.objects.filter(order_id=order.order_id)
for order_sku in order_skus:
# 计算小计
amount = order_sku.count * order_sku.price
order_sku.amount = amount
# 保存单个订单商品的信息
order.status_name = OrderInfo.ORDER_STATUS[order.order_status]
order.order_skus = order_skus
# 进行分页
paginator = Paginator(orders, 1)
# 获取第page页的内容
try:
page = int(page)
except Exception as e:
page = 1
if page > paginator.num_pages:
page = 1
# 获取第page页的page对象,废弃因为会加载所有的页码
order_page = paginator.page(page)
# 控制限制的页码,只显示最多5个按钮
# 如果总页数小于5,显示[1-页码]
# 如果当前页是前三页,显示[1,2,3,4,5]
# 如果当前页是后三页,显示[4,5,6,7,8] num_pages-4 到num_oages+1
# 显示当前页,显示当前页的前两页和后两页 [2,3,4,5,6]
num_pages = paginator.num_pages
if num_pages < 5:
pages = range(1, num_pages + 1)
elif num_pages <= 3:
pages = range(1, 6)
elif num_pages - page <= 2:
pages = range(num_pages-4, num_pages+1)
else:
pages = range(page-2, page+3)
context = {
'order_page': order_page,
'pages': pages,
'page': 'order',
}
return render(request, 'user_center_order.html', context)
订单支付_获取支付结果
支付流程
配置支付宝支付接口
文档 https://github.com/fzlee/alipay
openssl操作
沙箱环境
首先,进入蚂蚁金服开放平台官方主页, 点击文档中心的开发文档,往下翻,找到开发工具-沙箱环境
- 将本地公钥alipay_public_key.pem 内容设置为 查看公钥内容
-----BEGIN PUBLIC KEY-----
内容
-----END PUBLIC KEY-----
- 将 查看支付宝公钥复制本地 alipay_public_key.pem
- 将本地 app_private_key.pem文件复制项目中
- 遇到的错误:
RSA key format is not supported
设置沙箱买家 购买
前后台代码逻辑
class OrderPayView(View):
"""订单支付"""
def post(self, request):
# 判断用户是否登录
user = request.user
if not user.is_authenticated:
return JsonResponse({'res': 0, 'errmsg': '用户未登录'})
# 接受参数
order_id = request.POST.get('order_id')
# 判断参数
if not order_id:
return JsonResponse({'res': 1, 'errmsg': '无效订单id'})
try:
order = OrderInfo.objects.get(
order_id=order_id,
user=user,
pay_method=3,
order_status=1,
)
except OrderInfo.DoesNotExist as e:
return JsonResponse({'res': 2, 'errmsg': '订单错误,无此订单或需要支付宝付款'})
# 调用支付宝的支付接口
alipay = AliPay(
appid="你的APPID",
# 默认回调url
app_notify_url=None,
app_private_key_path=os.path.join(settings.BASE_DIR, 'apps/order/app_private_key.pem'),
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_path=os.path.join(settings.BASE_DIR, 'apps/order/alipay_public_key.pem'),
# RSA 或者 RSA2,官网推荐rsa2
sign_type="RSA",
debug=True # 默认False, true表示访问沙箱的dev接口
)
# 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string
total_pay = order.total_price + order.transit_price
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=order_id,
total_amount=str(total_pay),
subject='天天生鲜%s' % order_id,
return_url=None, # "https://example.com",
notify_url=None # "https://example.com/notify" # 可选, 不填则使用默认notify url
)
# 返回应答,引导html页面跳转去接受支付的dev界面
pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
return JsonResponse({'res': 3, 'pay_url': pay_url})
{% block bottomfiles %}
<script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script>
$('.oper_btn').each(function () {
// 获取支付状态
status = $(this).attr('status');
if (status == 1){
$(this).text('去支付')
}
else if (status == 4){
$(this).text('去评价')
}
else if (status == 5){
$(this).text('已完成')
}
});
$('.oper_btn').click(function () {
// 获取status
status = $(this).attr('status');
// 获取订单id
order_id = $(this).attr('order_id');
if (status == 1){
// 进行支付
csrf = $('input[name="csrfmiddlewaretoken"]').val();
// 组织参数
params = {'order_id':order_id, 'csrfmiddlewaretoken':csrf};
// 发起ajax post请求,访问/order/pay, 传递参数:order_id
$.post('/order/pay', params, function (data) {
if (data.res == 3){
// 引导用户到支付页面
window.open(data.pay_url);
// 浏览器访问/order/check, 获取支付交易的结果
// ajax post 传递参数:order_id
$.post('/order/check', params, function (data){
if (data.res == 3){
alert('支付成功');
// 刷新页面
location.reload()
}
else{
alert(data.errmsg)
}
})
}
else{
alert(data.errmsg)
}
})
}
else if (status == 4){
// 其他情况
// 跳转到评价页面
location.href = '/order/comment/'+order_id
}
})
</script>
{% endblock bottomfiles %}
获取支付结果
查看开发者文档
# ajax post
# 前端传递参数 order_id
# /order/check
class CheckPayView(View):
"""因为没有公网,所以下订单后手动去访问去query支付结果么人不是根据return_url"""
def post(self, request):
# 判断用户是否登录
user = request.user
if not user.is_authenticated:
return JsonResponse({'res': 0, 'errmsg': '用户未登录'})
# 接受参数
order_id = request.POST.get('order_id')
# 判断参数
if not order_id:
return JsonResponse({'res': 1, 'errmsg': '无效订单id'})
try:
order = OrderInfo.objects.get(
order_id=order_id,
user=user,
pay_method=3,
order_status=1,
)
except OrderInfo.DoesNotExist as e:
return JsonResponse({'res': 2, 'errmsg': '订单错误'})
# 调用支付宝的支付接口
alipay = AliPay(
appid="你的APPID",
# 默认回调url
app_notify_url=None,
app_private_key_path=os.path.join(settings.BASE_DIR, 'apps/order/app_private_key.pem'),
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_path=os.path.join(settings.BASE_DIR, 'apps/order/alipay_public_key.pem'),
# RSA 或者 RSA2,官网推荐rsa2
sign_type="RSA",
debug=True # 默认False, true表示访问沙箱的dev接口
)
# 手动查询结果
# 调用支付宝的交易查询接口
while True:
response = alipay.api_alipay_trade_query(order_id)
# response = {
# "trade_no": "2017032121001004070200176844", # 支付宝交易号
# "code": "10000", # 接口调用是否成功
# "invoice_amount": "20.00",
# "open_id": "20880072506750308812798160715407",
# "fund_bill_list": [
# {
# "amount": "20.00",
# "fund_channel": "ALIPAYACCOUNT"
# }
# ],
# "buyer_logon_id": "csq***@sandbox.com",
# "send_pay_date": "2017-03-21 13:29:17",
# "receipt_amount": "20.00",
# "out_trade_no": "out_trade_no15",
# "buyer_pay_amount": "20.00",
# "buyer_user_id": "2088102169481075",
# "msg": "Success",
# "point_amount": "0.00",
# "trade_status": "TRADE_SUCCESS", # 支付结果
# "total_amount": "20.00"
# }
code = response.get('code')
if code == '10000' and response.get('trade_status') == 'TRADE_SUCCESS':
# 支付成功
# 获取支付宝交易号
trade_no = response.get('trade_no')
# 更新订单状态
order.trade_no = trade_no
order.order_status = 4 # 待评价
order.save()
# 返回结果
return JsonResponse({'res': 3, 'message': '支付成功'})
elif code == '40004' or (code == '10000' and response.get('trade_status') == 'WAIT_BUYER_PAY'):
# 等待买家付款
# 业务处理失败,可能一会就会成功
import time
time.sleep(5)
continue
else:
# 支付出错
print(code)
return JsonResponse({'res': 4, 'errmsg': '支付失败'})
{% block bottomfiles %}
<script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script>
$('.oper_btn').each(function () {
// 获取支付状态
status = $(this).attr('status');
if (status == 1){
$(this).text('去支付')
}
else if (status == 4){
$(this).text('去评价')
}
else if (status == 5){
$(this).text('已完成')
}
});
$('.oper_btn').click(function () {
// 获取status
status = $(this).attr('status');
// 获取订单id
order_id = $(this).attr('order_id');
if (status == 1){
// 进行支付
csrf = $('input[name="csrfmiddlewaretoken"]').val();
// 组织参数
params = {'order_id':order_id, 'csrfmiddlewaretoken':csrf};
// 发起ajax post请求,访问/order/pay, 传递参数:order_id
$.post('/order/pay', params, function (data) {
if (data.res == 3){
// 引导用户到支付页面
window.open(data.pay_url);
// 浏览器访问/order/check, 获取支付交易的结果
// ajax post 传递参数:order_id
$.post('/order/check', params, function (data){
if (data.res == 3){
alert('支付成功');
// 刷新页面
location.reload()
}
else{
alert(data.errmsg)
}
})
}
else{
alert(data.errmsg)
}
})
}
else if (status == 4){
// 其他情况
// 跳转到评价页面
location.href = '/order/comment/'+order_id
}
})
</script>
{% endblock bottomfiles %}
订单评论
/user/order/1
支付js文件
{% block bottomfiles %}
<script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script>
$('.oper_btn').each(function () {
// 获取支付状态
status = $(this).attr('status');
if (status == 1){
$(this).text('去支付')
}
else if (status == 4){
$(this).text('去评价')
}
else if (status == 5){
$(this).text('已完成')
}
});
$('.oper_btn').click(function () {
// 获取status
status = $(this).attr('status');
// 获取订单id
order_id = $(this).attr('order_id');
if (status == 1){
// 进行支付
csrf = $('input[name="csrfmiddlewaretoken"]').val();
// 组织参数
params = {'order_id':order_id, 'csrfmiddlewaretoken':csrf};
// 发起ajax post请求,访问/order/pay, 传递参数:order_id
$.post('/order/pay', params, function (data) {
if (data.res == 3){
// 引导用户到支付页面
window.open(data.pay_url);
// 浏览器访问/order/check, 获取支付交易的结果
// ajax post 传递参数:order_id
$.post('/order/check', params, function (data){
if (data.res == 3){
alert('支付成功');
// 刷新页面
location.reload()
}
else{
alert(data.errmsg)
}
})
}
else{
alert(data.errmsg)
}
})
}
else if (status == 4){
// 其他情况
// 跳转到评价页面
location.href = '/order/comment/'+order_id
}
})
</script>
{% endblock bottomfiles %}
评论 order_comment.html
{% extends 'base_user_center.html' %}
{% load staticfiles %}
{% block title %}天天生鲜-用户中心{% endblock %}
{% block page_title %}用户中心{% endblock page_title %}
{% block right_content %}
<div class="right_content clearfix">
<h3 class="common_title2">订单评价</h3>
<ul class="order_list_th w978 clearfix">
<li class="col01">{{order.create_time}}</li>
<li class="col02">订单号:{{order.order_id}}</li>
<li class="col02 stress">{{order.status_name}}</li>
</ul>
<form method="post">
{% csrf_token %}
{# 订单id #}
<input type="hidden" name="order_id" value="{{order.order_id}}">
{# 订单中有几个商品 #}
<input type="hidden" name="total_count" value="{{order.order_skus|length}}">
{% for order_sku in order.order_skus %}
<table class="order_list_table w980">
<tbody>
<tr>
<td width="80%">
<ul class="order_goods_list clearfix">
<li class="col01"><img src="{{ order_sku.sku.image.url }}"></li>
<li class="col02">{{order_sku.sku.name}}<em>{{order_sku.price}}/{{order_sku.sku.unite}}</em></li>
<li class="col03">{{order_sku.count}}</li>
</ul>
</td>
<td width="20%">{{order_sku.amount}}元</td>
</tr>
</tbody>
</table>
<div class="site_con">
<input type="hidden" name="sku_{{forloop.counter}}" value="{{order_sku.sku.id}}">
<div class="form_group form_group2">
<label>评价内容:</label>
<textarea class="site_area" name="content_{{forloop.counter}}"></textarea>
</div>
</div>
{% endfor %}
<input type="submit" name="" value="提交" class="info_submit">
</form>
</div>
{% endblock right_content %}
评论后端逻辑
class CommentView(View):
"""订单评论"""
def get(self, request, order_id):
"""提供评论页面"""
user = request.user
# 校验数据
if not order_id:
return redirect(reverse('user:order'))
try:
order = OrderInfo.objects.get(order_id=order_id, user=user)
except OrderInfo.DoesNotExist:
return redirect(reverse("user:order"))
# 根据订单的状态获取订单的状态标题
order.status_name = OrderInfo.ORDER_STATUS[order.order_status]
# 获取订单商品信息
order_skus = OrderGoods.objects.filter(order_id=order_id)
for order_sku in order_skus:
# 计算商品的小计
amount = order_sku.count*order_sku.price
# 动态给order_sku增加属性amount,保存商品小计
order_sku.amount = amount
# 动态给order增加属性order_skus, 保存订单商品信息
order.order_skus = order_skus
# 使用模板
return render(request, "order_comment.html", {"order": order})
def post(self, request, order_id):
"""处理评论内容"""
user = request.user
# 校验数据
if not order_id:
return redirect(reverse('user:order'))
try:
order = OrderInfo.objects.get(order_id=order_id, user=user)
except OrderInfo.DoesNotExist:
return redirect(reverse("user:order"))
# 获取评论条数
total_count = request.POST.get("total_count")
total_count = int(total_count)
# 循环获取订单中商品的评论内容
for i in range(1, total_count + 1):
# 获取评论的商品的id
sku_id = request.POST.get("sku_%d" % i) # sku_1 sku_2
# 获取评论的商品的内容
content = request.POST.get('content_%d' % i, '') # cotent_1 content_2 content_3
try:
order_goods = OrderGoods.objects.get(order=order, sku_id=sku_id)
except OrderGoods.DoesNotExist:
continue
order_goods.comment = content
order_goods.save()
order.order_status = 5 # 已完成
order.save()
return redirect(reverse("user:order", kwargs={"page": 1}))
评论后商品详情
点击商品介绍或者评论 按钮,另一个移除
<script type="text/javascript">
$('#tag_detail').click(function () {
$('#tag_comment').removeClass('active')
$(this).addClass('active')
$('#tab_detail').show()
$('#tab_comment').hide()
})
$('#tag_comment').click(function () {
$('#tag_detail').removeClass('active')
$(this).addClass('active')
$('#tab_detail').hide()
$('#tab_comment').show()
})