总计价格计算
计算购物车中被选中的商品的价格采取:后端必须算,前端选算。
用一个函数计算商品总价格
views_helper:
def get_total_price():
# 找到被选中的商品
carts = Cart.objects.filter(c_is_select=True)
total = 0
for cart in carts:
total += cart.c_goods_num*cart.c_goods.price
return total
views:导入上述函数
def cart(request):
carts = Cart.objects.filter(c_user=request.user)
# 判断是不是全部被选中,全部被选中就返回True
is_all_select = not carts.filter(c_is_select=False).exists()
data = {
'title': '购物车',
'carts': carts,
'is_all_select': is_all_select,
'total_price': get_total_price(),
}
return render(request, 'main/cart.html', context=data)
接下来来到cart.html中将价格传入页面:
cart:
<p>
<span>全选</span>
<span>共计:</span>
<span id="total_price">{{ total_price }}</span>
</p>
下面我们要将计算总价的函数放入所有需要返回价格的地方:
views:
def allselect(request):
cart_list = request.GET.get('cart_list')
cart_list = cart_list.split('#')
carts = Cart.objects.filter(id__in=cart_list) # 这样查询数据库的次数变少
for cart_obj in carts:
cart_obj.c_is_select = not cart_obj.c_is_select
cart_obj.save()
data = {
'status': 200,
'msg': 'ok',
'total_price': get_total_price(),
}
return JsonResponse(data=data)
def subshopping(request):
# 接受cartid
cartid = request.GET.get('cartid')
# 从数据库中查找到对应的
cart_obj = Cart.objects.get(pk=cartid)
data = {
'status': 200,
'msg': 'ok',
}
# 判断数据库中商品数量
if cart_obj.c_goods_num > 1: # 如果数量大于1就减少1
cart_obj.c_goods_num = cart_obj.c_goods_num - 1
cart_obj.save()
data['c_goods_num'] = cart_obj.c_goods_num
else: # 如果数量小于等于1就从数据库中删除
cart_obj.delete()
data['c_goods_num'] = 0
data['total_price'] = get_total_price()
return JsonResponse(data=data)
def change_cart_state(request):
# 从ajax获得商品id,但是这里有个隐藏漏洞,这里没有验证这个cart_id是用户已经存在的
cart_id = request.GET.get('cartid')
# 去数据库中匹配对应的商品id
cart_obj = Cart.objects.get(pk=cart_id)
# 将原本选中的状态取反
cart_obj.c_is_select = not cart_obj.c_is_select
# 记得保存,如果不保存,数据库的状态不会改变
cart_obj.save()
# 判断这个商品是否被选中
is_all_select = not Cart.objects.filter(c_user=request.user).filter(c_is_select=False).exists()
data = {
'status': 200,
'msg': 'change ok',
'c_is_select': cart_obj.c_is_select,
'is_all_select': is_all_select,
'total_price': get_total_price(),
}
return JsonResponse(data=data)
前端价格联动
修改完商品数量之后,需要实时在客户的界面更新价格。
cart.js:
$(function(){
$('.confirm').click(function(){
console.log('change state');
/*修改选中状态*/
var $confirm = $(this);
var $li = $confirm.parents('li');
var cartid = $li.attr('cartid');
/*利用ajax,找到对应标签之后发送给服务器修改状态*/
$.getJSON('/peiqi1/changecartstate/',{'cartid': cartid}, function (data){
console.log(data);
if (data['status']===200){
$('#total_price').html(data['total_price']); //实时更新价格
if(data['c_is_select']){
$confirm.find('span').find('span').html('√');
}else{
$confirm.find('span').find('span').html('');
}
if (data['is_all_select']){
$('.all_select span span').html('√');
}else{
$('.all_select span span').html('');
}
}
})
})
$('.subShopping').click(function (){
var $sub = $(this);
var $li = $sub.parents('li');
var cartid = $li.attr('cartid');
$.getJSON('/peiqi1/subshopping/', {'cartid':cartid}, function(data){
console.log(data);
/*把修改之后的数量传回用户所在的前端页面*/
if (data['status']===200){
$('#total_price').html(data['total_price']); //实时更新价格
if (data['c_goods_num']> 0){
var $span = $sub.next('span');
$span.html(data['c_goods_num']);
}else{
$li.remove();
}
}
})
})
$('.all_select').click(function(){
var $all_select = $(this);
// 点击全选按钮,如果有未选中就变成选中的,如果是全选中的就变成所有的都未选中
var select_list = [];
var unselect_list = [];
$('.confirm').each(function(){
var $confirm = $(this);
var cartid = $confirm.parents('li').attr('cartid');
if($confirm.find('span').find('span').html().trim()){
//将选中的加入选中的表
select_list.push(cartid);
}else{ //将未选中的加入未选中表
unselect_list.push(cartid);
}
}) //遍历
//当没有选中的列表大于0,就将unselect_list发送给服务器改为选中
if(unselect_list.length>0){
$.getJSON('/peiqi1/allselect', {'cart_list': unselect_list.join('#')}, function (data){
console.log(data);
if(data['status']===200){
$('.confirm').find('span').find('span').html('√'); //按下全选,将所有的按钮都改为选中
$all_select.find('span').find('span').html('√');
$('#total_price').html(data['total_price']); //实时更新价格
}
})
}else{
if (select_list.length>0){
$.getJSON('/peiqi1/allselect', {'cart_list': select_list.join('#')}, function (data){
console.log(data);
if(data['status']===200){
$('.confirm').find('span').find('span').html(''); //取消全选,将所有选中改为未选中
$all_select.find('span').find('span').html('');
$('#total_price').html(data['total_price']); //实时更新价格
}
})
}
}
})
})
在200状态之后都要计算一次总价,所以在其后加上 $('#total_price').html(data['total_price']);
下单功能
点击下单,将我们选中的商品从购物车表中移除,并且生成订单表。
我们将下单按钮换成span按钮,采用ajax去完成
<span id="make_order">下单</span>
然后我们需要去用js找到这个标签:
cart.js:
$('#make_order').click(function (){
//判断选中还是未选中
var select_list = [];
var unselect_list = [];
$('.confirm').each(function(){
var $confirm = $(this);
var cartid = $confirm.parents('li').attr('cartid');
if($confirm.find('span').find('span').html().trim()){
//将选中的加入选中的表
select_list.push(cartid);
}else{ //将未选中的加入未选中表
unselect_list.push(cartid);
}
}) //遍历
if(select_list.length===0){
return //如果下单时没有选中商品就删除
}
// 购物车商品不为空,就把数据发送给服务端
$.getJSON('/peiqi1/makeorder/', function(data){
console.log(data);
})
然后我们需要写url接口:
urls新建:
url(r'^makeorder/', views.make_order, name='make_order'),
将该接口加入中间件中:
REQUIRE_LOGIN_JSON = [
'/peiqi1/addtocart/',
'/peiqi1/changecartstate/',
'/peiqi1/makeorder/',
]
在views_contant中添加订单状态简称:
# 已下单未付款
ORDER_STATUS_NOT_PAY = 1
# 已下单已付款未发货
ORDER_STATUS_NOT_SEND = 2
# 已下单已付款已发货未收货
ORDER_STATUS_NOT_RECEIVE = 3
# 已下单已付款已发货已收货未确认
# 已下单已付款已发货已收货已确认
# 已下单已付款已发货已收货已确认未评论
# 已下单已付款已发货已收货已确认已评论未追评
# 已下单已付款已发货已收货已确认已评论
# 申请售后
# 退货
# 换货
# 返修
创建订单models:
class Order(models.Model):
o_user = models.ForeignKey(peiqi1user) # 用户
o_price = models.FloatField(default=0) # 总价
o_time = models.DateTimeField(auto_now=True) # 订单创建日期
o_status = models.IntegerField(default=ORDER_STATUS_NOT_PAY)
class Meta:
db_table = 'peiqi1_order'
class OrderGoods(models.Model):
o_order = models.ForeignKey(Order)
o_goods = models.ForeignKey(Goods)
o_goods_num = models.IntegerField(default=1)
class Meta:
db_table = 'peiqi1_ordergoods'
然后迁移数据库
views:
def make_order(request):
# 先将所有商品取出来
carts = Cart.objects.filter(c_user=request.user).filter(c_is_select=True)
# 将商品放入订单表中
order = Order()
order.o_user = request.user
order.o_price = get_total_price()
order.save()
# 商品级联
for cart_obj in carts:
ordergoods = OrderGoods()
ordergoods.o_order = order
ordergoods.o_goods_num = cart_obj.c_goods_num
ordergoods.o_goods = cart_obj.c_goods
ordergoods.save()
cart_obj.delete()
data = {
'status': 200,
'msg': 'ok',
'order_id': order.id
}
return JsonResponse(data)
测试能否生成订单号:
观察数据库order表
订单详情页面
订单生成之后用户界面需要跳转到订单详情页面。
cart.js:
$.getJSON('/peiqi1/makeorder/', function(data){
console.log(data);
if(data['status']===200){
window.open('/peiqi1/orderdetail/?orderid=' + data['oder_id'], target='_self');
}
})
接下来新建url:
url(r'^orderdetail/', views.order_detail, name='order_detail'),
因为订单详情需要验证用户登录,将url添加到中间件中:
REQUIRE_LOGIN = [
'/peiqi1/cart/',
'/peiqi1/orderdetail',
]
接着新建模板文件夹order,以及base_orderdetail.html,和orderdetail.html
base_orderdetail.html:
{% extends 'base.html' %}
orderdetail.html:
{% extends 'base_order.html' %}
views:
def order_detail(request):
# 获取orderid
order_id = request.GET.get('orderid')
order = Order.objects.get(pk=order_id)
data = {
'title': '订单详情',
'order': order,
}
return render(request, 'order/order_detail.html')
现在我们完成了骨架的架构,下面编写订单详情页面
新建order静态资源文件夹及其css子文件夹,并且新建order_detail.css:
/
order_detail.css:
/**************menu***************/
.menuList {
border-bottom: 0.04rem solid lightgrey;
height: 2.5rem;
position: relative;
}
.confirm, .all_select{
padding: 0.95rem 0;
width: 15%;
height: 2.5rem;
display: inline-block;
box-sizing: border-box;
text-align: center;
float: left;
}
.confirm > span, .all_select>span{
box-sizing: border-box;
border: 0.04rem solid orange;
background: white;
display: inline-block;
width: 0.6rem;
height: 0.6rem;
overflow: hidden;
border-radius: 50%;
line-height: 0.6rem;
}
.confirm > span > span, .all_select>span>span {
background: yellow;
font-size: 0.5rem;
display: block;
}
.menuList > a {
width: 84%;
display: inline-block;
font-size: 0.4rem;
line-height: 1rem;
}
.menuList > a > img {
margin-top: 0.25rem;
width: 25%;
height: 100%;
float: left;
}
.menuList > a > p {
width: 70%;
height: 1rem;
float: right;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.menuList > section {
position: absolute;
right: 0.4rem;
bottom: 0.4rem;
height: 0.75rem;
border-radius: 1rem;
}
.menuList > section > button {
background: white;
border: 1px solid orange;
border-radius: 1111px;
color: red;
display: inline-block;
text-align: center;
line-height: 0.65rem;
font-weight: 900;
width: 0.75rem;
height: 0.75rem;
}
.menuList > section > span {
display: inline-block;
width: 0.5rem;
text-align: center;
line-height: 0.5rem;
font-size: 0.4rem;
}
.presentPrice:before {
content: "¥";
font-size: 0.33rem;
}
/*************payTheBill 买单*************/
.payTheBill {
height: 1.5rem;
position: relative;
}
.payTheBill .all_select {
width: 10%;
padding-top: 0.4rem;
padding-left: 0.4rem;
}
.payTheBill > p {
line-height: 1.5rem;
text-indent: 0.3rem;
}
.payTheBill > p > span:first-child {
padding-right: 0.8rem;
}
.payTheBill > p > span:last-child {
padding-left: 0.3rem;
color: red;
}
.payTheBill > p > span:last-child:before {
content: "¥";
font-size: 0.35rem;
}
.payTheBill > span {
background: yellow;
position: absolute;
right: 0;
line-height: 1.5rem;
top: 0;
padding: 0 0.7rem;
}
oder_detail.html:
{% extends 'base_order.html' %}
{% load static %}
{# 导入css #}
{% block ext_css %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'peiqi1/order/css/order_detail.css' %}">
{% endblock %}
{% block content %}
<div id='order_detail' class="container">
<h6>订单编号:{{ order.id }}</h6>
{# 取出商品信息 #}
<ul>
{% for ordergoods in order.ordergoods_set.all %}
<li class="menuList">
<a href="#">
<img src="{{ ordergoods.o_goods.productimg }}" alt="{{ ordergoods.c_goods.productlongname }}">
<p>{{ ordergoods.o_goods.productlongname }}</p>
<p class="presentPrice">{{ ordergoods.o_goods.price }}</p>
</a>
<section>
<span>{{ ordergoods.o_goods_num }}</span>
</section>
</li>
{% endfor %}
</ul>
<h6 class="total_price">总价:<span id="total_price">{{ order.o_price }}</span></h6>
<button class="btn btn-success btn-block">支付</button>
</div>
{% endblock %}
base_order.css:
{% extends 'base.html' %}
{% load static %}
{% block ext_css %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'peiqi1/order/css/order.css' %}">
{% endblock %}
{% block header %}
<header></header>
{% endblock %}
新建order.css
order.css:
header{
height: 1.5rem;
background: #2fea83;
margin-bottom: 0.3rem;
}
测试:
此处评论已关闭