# 项目的urls url(r'^cart/', include('cart.urls', namespace='cart')),
# 应用的urls urlpatterns = [ url(r'^add$', views.AddCartView.as_view(), name='add') ]
class AddCartView(View): """添加到购物车""" def post(self, request): # 判断用户是否登录 # 接收数据:user_id,sku_id,count # 校验参数all() # 判断商品是否存在 # 判断count是不是整数 # 判断库存 # 操做redis数据库存储商品到购物车 # json方式响应添加购物车结果 pass
LoginRequiredMixin
AddCartView
时,须要是登录状态LoginRequiredMixin
验证以后的结果是以重定向的方式告诉客户端的GoodsSKU.DoesNotExist
Exception
origin_count = redis_conn.hget("cart_%s" %user_id, sku_id)
origin_count
为bytes
类型的,若是作加减操做须要转成int(origin_count)
bytes
类型的,若是作加减操做须要转成整数class AddCartView(View): """添加购物车""" def post(self, request): # 判断用户是否登录 if not request.user.is_authenticated(): return JsonResponse({'code': 1, 'message':'用户未登陆'}) # 接收数据:user_id,sku_id,count user_id = request.user.id sku_id = request.POST.get('sku_id') count = request.POST.get('count') # 校验参数 if not all([sku_id,count]): return JsonResponse({'code': 2, 'message': '参数不完整'}) # 判断商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: return JsonResponse({'code': 3, 'message': '商品不存在'}) # 判断count是不是整数 try: count = int(count) except Exception: return JsonResponse({'code': 4, 'message': '数量错误'}) # 判断库存 # if count > sku.stock: # return JsonResponse({'code': 5, 'message': '库存不足'}) # 操做redis数据库存储商品到购物车 redis_conn = get_redis_connection('default') # 须要先获取要添加到购物车的商品是否存在 origin_count = redis_conn.hget('cart_%s'%user_id, sku_id) # 若是商品在购物车中存在,就直接累加商品数量;反之,把新的商品和数量添加到购物车 if origin_count is not None: count += int(origin_count) # 判断库存:计算最终的count与库存比较 if count > sku.stock: return JsonResponse({'code': 5, 'message': '库存不足'}) # 存储到redis redis_conn.hset('cart_%s'%user_id, sku_id, count) # 为了配合模板中js交互并展现购物车的数量,在这里须要查询一下购物车的总数 cart_num = 0 cart_dict = redis_conn.hgetall('cart_%s'%user_id) for val in cart_dict.values(): cart_num += int(val) # json方式响应添加购物车结果 return JsonResponse({'code': 0, 'message': '添加购物车成功', 'cart_num':cart_num})
$('#add_cart').click(function(){ // 将商品的id和数量发送给后端视图,后端进行购物车数据的记录 // 获取商品的id和数量 var request_data = { sku_id: $('#add_cart').attr('sku_id'), count: $('#num_show').val(), csrfmiddlewaretoken: "{{ csrf_token }}" }; // 使用ajax向后端发送数据 $.post('/cart/add', request_data, function (response_data) { // 根据后端响应的数据,决定处理效果 if (1 == response_data.code){ location.href = '/users/login'; // 若是未登陆,跳转到登陆页面 } else if (0 == response_data.code) { $(".add_jump").stop().animate({ 'left': $to_y+7, 'top': $to_x+7}, "fast", function() { $(".add_jump").fadeOut('fast',function(){ // 展现购物车总数量 $('#show_count').html(response_data.cart_num); }); }); } else { // 其余错误信息,简单弹出来 alert(response_data.message); } }); });
'cart':'{'sku_1':10, 'sku_2':20}'
# 向浏览器中写入购物车cookie信息 response.set_cookie('cart', cart_str)
。。。 # 读取cookie中的购物车信息 cart_json = request.COOKIES.get('cart')
实现:json模块javascript
1.先从cookie中,获取当前商品的购物车记录 (cart_json) 2.判断购物车(cart_json)数据是否存在,有可能用户历来没有操做过购物车 2.1.若是(cart_json)存在就把它转成字典(cart_dict) 2.2.若是(cart_json)不存在就定义空字典(cart_dict) 3.判断要添加的商品在购物车中是否存在 3.1.若是存在就取出源有值,并进行累加 3.2.若是不存在就直接保存商品数量 4.将(cart_dict)从新生成json字符串,方便写入到cookie 5.建立JsonResponse对象,该对象就是要响应的对象 6.在响应前,设置cookie信息 7.计算购物车数量总和,方便前端展现
if not request.user.is_authenticated(): # 若是用户未登陆,就保存购物车数据到cookie中 # 先从cookie的购物车信息中,获取当前商品的购物车记录,即json字符串购物车数据 cart_json = request.COOKIES.get('cart') # 判断购物车cookie数据是否存在,有可能用户历来没有操做过购物车 if cart_json is not None: # 将json字符串转成json字典 cart_dict = json.loads(cart_json) else: # 若是用户没有操做购物车,就给个空字典 cart_dict = {} if sku_id in cart_dict: # 若是cookie中有这个商品记录,则直接进行求和;若是cookie中没有这个商品记录,则将记录设置到购物车cookie中 origin_count = cart_dict[sku_id] # json模块,存进去的是数字,取出来的也是数字 count += origin_count # 判断库存:计算最终的count与库存比较 if count > sku.stock: return JsonResponse({'code': 6, 'message': '库存不足'}) # 设置最终的商品数量到购物车 cart_dict[sku_id] = count # 计算购物车总数 cart_num = 0 for val in cart_dict.values(): cart_num += int(val) # 将json字典转成json字符串 cart_str = json.dumps(cart_dict) # 将购物车数据写入到cookie中 response = JsonResponse({"code": 0, "message": "添加购物车成功", 'cart_num': cart_num}) response.set_cookie('cart', cart_str) return response
class AddCartView(View): """添加到购物车: sku_id, count, user_id""" def post(self, request): # 判断用户是否登陆 # if not request.user.is_authenticated(): # # 提示用户未登陆 # return JsonResponse({"code": 1, "message": "用户未登陆"}) # 商品id sku_id = request.POST.get("sku_id") # 商品数量 count = request.POST.get("count") # 检验参数 if not all([sku_id, count]): return JsonResponse({"code": 2, "message": "参数不完整"}) # 判断商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 表示商品不存在 return JsonResponse({"code": 3, "message": "商品不存在"}) # 判断count是整数 try: count = int(count) except Exception: return JsonResponse({"code": 4, "message": "参数错误"}) # 判断库存 # if count > sku.stock: # return JsonResponse({"code": 5, "message": "库存不足"}) # 提示:不管是否登录状态,都须要获取suk_id,count,校验参数。。。 # 因此等待参数校验结束后,再来判断用户是否登录 # 若是用户已登陆,就保存购物车数据到redis中 if request.user.is_authenticated(): # 用户id user_id = request.user.id # "cart_用户id": {"sku_1": 10, "sku_2": 11} # 先尝试从用户的购物车中获取这个商品的数量,若是购物车中不存在这个商品,则直接添加购物车记录 # 不然,须要进行数量的累计,在添加到购物车记录中 redis_conn = get_redis_connection("default") origin_count = redis_conn.hget("cart_%s" % user_id, sku_id) # 原有数量 if origin_count is not None: count += int(origin_count) # 判断库存:计算最终的count与库存比较 if count > sku.stock: return JsonResponse({'code': 5, 'message': '库存不足'}) # 存储到redis redis_conn.hset("cart_%s" % user_id, sku_id, count) # 为了方便前端展现购物车数量,因此查询一下购物车总数 cart_num = 0 cart = redis_conn.hgetall("cart_%s" % user_id) for val in cart.values(): cart_num += int(val) # 采用json返回给前端 return JsonResponse({"code": 0, "message": "添加购物车成功", "cart_num": cart_num}) else: # 若是用户未登陆,就保存购物车数据到cookie中 # 先从cookie的购物车信息中,获取当前商品的记录,json字符串购物车数据 cart_json = request.COOKIES.get('cart') # 判断购物车cookie数据是否存在,有可能用户历来没有操做过购物车 if cart_json is not None: # 将json字符串转成json字典 cart_dict = json.loads(cart_json) else: # 若是用户没有操做购物车,就给个空字典 cart_dict = {} if sku_id in cart_dict: # 若是cookie中有这个商品记录,则直接进行求和;若是cookie中没有这个商品记录,则将记录设置到购物车cookie中 origin_count = cart_dict[sku_id] count += origin_count # 判断库存:计算最终的count与库存比较 if count > sku.stock: return JsonResponse({'code': 6, 'message': '库存不足'}) # 设置最终的商品数量到购物车 cart_dict[sku_id] = count # 计算购物车总数 cart_num = 0 for val in cart_dict.values(): cart_num += val # 将json字典转成json字符串 cart_str = json.dumps(cart_dict) # 将购物车数据写入到cookie中 response = JsonResponse({"code": 0, "message": "添加购物车成功", 'cart_num': cart_num}) response.set_cookie('cart', cart_str) return response
不须要再判断是不是登录用户html
$('#add_cart').click(function(){ // 将商品的id和数量发送给后端视图,后端进行购物车数据的记录 // 获取商品的id和数量 var request_data = { sku_id: $(this).attr('sku_id'), count: $('#num_show').val(), csrfmiddlewaretoken: "" }; // 使用ajax向后端发送数据 $.post('/cart/add', request_data, function (response_data) { // 根据后端响应的数据,决定处理效果 if (0 == response_data.code) { $(".add_jump").stop().animate({ 'left': $to_y+7, 'top': $to_x+7}, "fast", function() { $(".add_jump").fadeOut('fast',function(){ // 展现购物车总数量 $('#show_count').html(response_data.cart_num); }); }); } else { // 其余错误信息,简单弹出来 alert(response_data.message); } }); });
提示:商品模块的购物车包括,主页
、详情页
、列表页
前端
因为主页
、详情页
、列表页
中都涉及到购物车数据的展现java
因此,将购物车逻辑封装到基类BaseCartView
中python
class BaseCartView(View): """提供购物车数据统计功能""" def get_cart_num(self, request): cart_num = 0 # 若是用户登陆,就从redis中获取购物车数据 if request.user.is_authenticated(): # 建立redis_conn对象 redis_conn = get_redis_connection('default') # 获取用户id user_id = request.user.id # 从redis中获取购物车数据,返回字典,若是没有数据,返回None,因此不须要异常判断 cart = redis_conn.hgetall('cart_%s' %user_id) # 遍历购物车字典,累加购物车的值 for value in cart.values(): cart_num += int(value) else: # 若是用户未登陆,就从cookie中获取购物车数据 cart_json = request.COOKIES.get('cart') # json字符串 # 判断购物车数据是否存在 if cart_json is not None: # 将json字符串购物车数据转成json字典 cart_dict = json.loads(cart_json) else: cart_dict = {} # 遍历购物车字典,计算商品数量 for val in cart_dict.values(): cart_num += val return cart_num
修改了base.html
后,主页,详情页,列表页 都具有相同的数据mysql
# cookie 'cart':'{'sku_1':10, 'sku_2':20}'
若是用户已登陆,从redis中获取购物车数据jquery
cart_userid:{sku_3, 30}
url(r'^cart/', include('cart.urls', namespace='cart'))
url(r'^cart/', include('cart.urls', namespace='cart'))
class CartInfoView(View): """获取购物车数据""" def get(self, request): """提供购物车页面:不须要请求参数""" pass
class CartInfoView(View): """获取购物车数据""" def get(self, request): """提供购物车页面:不须要请求参数""" # 查询购物车数据 # 若是用户登录从redis中获取数据 if request.user.is_authenticated(): # 建立redis链接对象 redis_conn = get_redis_connection('default') user_id = request.user.id # 获取全部数据 cart_dict = redis_conn.hgetall('cart_%s'%user_id) else: # 若是用户未登录从cookie中获取数据 cart_json = request.COOKIES.get('cart') # 判断用户是否操做过购物车cookie if cart_json is not None: cart_dict = json.loads(cart_json) else: cart_dict = {} # 保存遍历出来的sku skus = [] # 总金额 total_amount = 0 # 总数量 total_count = 0 # 遍历cart_dict,造成模板所须要的数据 for sku_id, count in cart_dict.items(): # 查询商品sku try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 商品不存在,跳过这个商品,继续遍历 continue # 将count转成整数,由于redis中取出的count不是整数类型的 count = int(count) # 计算总价 amount = sku.price * count # 将须要展现的数据保存到对象中 sku.amount = amount sku.count = count # 生成模型列表 skus.append(sku) # 计算总金额 total_amount += amount # 计算总数量 total_count += count # 构造上下文 context = { 'skus':skus, 'total_amount':total_amount, 'total_count':total_count } return render(request, 'cart.html', context)
{% extends 'base.html' %} {% block title %}每天生鲜-购物车{% endblock %} {% load staticfiles %} {% block search_bar %} <div class="search_bar clearfix"> <a href="{% url 'goods:index' %}" class="logo fl"><img src="{% static 'images/logo.png' %}"></a> <div class="sub_page_name fl">| 购物车</div> <div class="search_con fr"> <form action="/search/" method="get"> <input type="text" class="input_text fl" name="q" placeholder="搜索商品"> <input type="submit" class="input_btn fr" value="搜索"> </form> </div> </div> {% endblock %} {% block body %} <div class="total_count">所有商品<em>{{total_count}}</em>件</div> <ul class="cart_list_th clearfix"> <li class="col01">商品名称</li> <li class="col02">商品单位</li> <li class="col03">商品价格</li> <li class="col04">数量</li> <li class="col05">小计</li> <li class="col06">操做</li> </ul> <form method="post" action="#"> {% csrf_token %} {% for sku in skus %} <ul class="cart_list_td clearfix" sku_id="{{ sku.id }}"> <li class="col01"><input type="checkbox" name="sku_ids" value="{{ sku.id }}" checked></li> <li class="col02"><img src="{{ sku.default_image.url }}"></li> <li class="col03">{{ sku.name }}<br><em>{{ sku.price }}/{{ sku.unit}}</em></li> <li class="col04">{{ sku.unit }}</li> <li class="col05"><span>{{sku.price}}</span>元</li> <li class="col06"> <div class="num_add"> <a href="javascript:;" class="add fl">+</a> <input type="text" class="num_show fl" sku_id="{{ sku.id }}" value="{{sku.count}}"> <a href="javascript:;" class="minus fl">-</a> </div> </li> <li class="col07"><span>{{sku.amount}}</span>元</li> <li class="col08"><a href="javascript:;" class="del_btn">删除</a></li> </ul> {% endfor %} <ul class="settlements"> <li class="col01"><input type="checkbox" checked></li> <li class="col02">全选</li> <li class="col03">合计(不含运费):<span>¥</span><em id="total_amount">{{total_amount}}</em><br>共计<b id="total_count">{{total_count}}</b>件商品</li> <li class="col04"><a href="place_order.html">去结算</a></li> </ul> </form> {% endblock %} {% block bottom_files %} <script type="text/javascript" src="{% static 'js/jquery-1.12.2.js' %}"></script> <script type="text/javascript"> // 更新页面合计信息 function freshOrderCommitInfo() { var total_amount = 0; //总金额 var total_count = 0; // 总数量 $('.cart_list_td').find(':checked').parents('ul').each(function () { var sku_amount = $(this).children('li.col07').text(); // 商品的金额 var sku_count = $(this).find('.num_show').val(); // 商品的数量 total_count += parseInt(sku_count); total_amount += parseFloat(sku_amount); }); // 设置商品的总数和总价 $("#total_amount").text(total_amount.toFixed(2)); $("#total_count").text(total_count); } // 更新页面顶端所有商品数量 function freshTotalGoodsCount() { var total_count = 0; $('.cart_list_td').find(':checkbox').parents('ul').each(function () { var sku_count = $(this).find('.num_show').val(); total_count += parseInt(sku_count); }); $(".total_count>em").text(total_count); } // 更新后端购物车信息 function updateRemoteCartInfo(sku_id, sku_count, num_dom) { // 发送给后端的数据 var req = { sku_id: sku_id, count: sku_count, csrfmiddlewaretoken: "{{ csrf_token }}" }; $.post("/cart/update", req, function(data){ if (0 == data.code) { // 更新商品数量 $(num_dom).val(sku_count); // 更新商品金额信息 var sku_price = $(".cart_list_td[sku_id="+sku_id+"]").children('li.col05').children().text(); var sku_amount = parseFloat(sku_price) * sku_count; $(".cart_list_td[sku_id="+sku_id+"]").children('li.col07').children().text(sku_amount.toFixed(2)); // 更新顶部商品总数 freshTotalGoodsCount(); // 更新底部合计信息 freshOrderCommitInfo(); } else { alert(data.message); } }); } // 增长 $(".add").click(function(){ // 获取操做的商品id var sku_id = $(this).next().attr("sku_id"); // 获取加操做前的的数量 var sku_num = $(this).next().val(); // 进行数量加1 sku_num = parseInt(sku_num); sku_num += 1; // 显示商品数目的dom var num_dom = $(this).next(); // 更新购物车数量 updateRemoteCartInfo(sku_id, sku_num, num_dom); }); // 减小 $(".minus").click(function(){ // 获取操做的商品id var sku_id = $(this).prev().attr("sku_id"); // 获取加操做前的的数量 var sku_num = $(this).prev().val(); // 进行数量加1 sku_num = parseInt(sku_num); sku_num -= 1; if (sku_num < 1) sku_num = 1; // 更新页面显示数量 var num_dom = $(this).prev(); // 更新购物车数量 updateRemoteCartInfo(sku_id, sku_num, num_dom); }); var pre_sku_count = 0; $('.num_show').focus(function () { // 记录用户手动输入以前商品数目 pre_sku_count = $(this).val(); }); // 手动输入 $(".num_show").blur(function(){ var sku_id = $(this).attr("sku_id"); var sku_num = $(this).val(); // 若是输入的数据不合理,则将输入值设置为在手动输入前记录的商品数目 if (isNaN(sku_num) || sku_num.trim().length<=0 || parseInt(sku_num)<=0) { $(this).val(pre_sku_count); return; } sku_num = parseInt(sku_num); var num_dom = $(this); updateRemoteCartInfo(sku_id, sku_num, num_dom); }); // 删除 $(".del_btn").click(function(){ var sku_id = $(this).parents("ul").attr("sku_id"); var req = { sku_id: sku_id, csrfmiddlewaretoken: "{{ csrf_token }}" }; $.post('/cart/delete', req, function(data){ // window.reload() location.href="/cart/"; // 删除后,刷新页面 }); }); // 商品对应checkbox发生改变时,全选checkbox发生改变 $('.cart_list_td').find(':checkbox').change(function () { // 获取商品全部checkbox的数目 var all_len = $('.cart_list_td').find(':checkbox').length; // 获取选中商品的checkbox的数目 var checked_len = $('.cart_list_td').find(':checked').length; if (checked_len < all_len){ // 有商品没有被选中 $('.settlements').find(':checkbox').prop('checked', false) } else{ // 全部商品都被选中 $('.settlements').find(':checkbox').prop('checked', true) } freshOrderCommitInfo(); }); // 全选和全不选 $('.settlements').find(':checkbox').change(function () { // 1.获取当前checkbox的选中状态 var is_checked = $(this).prop('checked'); // 2.遍历并设置商品ul中checkbox的选中状态 $('.cart_list_td').find(':checkbox').each(function () { // 设置每个goods ul中checkbox的值 $(this).prop('checked', is_checked) }); freshOrderCommitInfo(); }); </script> {% endblock %}
# 在页面跳转以前,将cookie中和redis中的购物车数据合并 # 从cookie中获取购物车数据 cart_json = request.COOKIES.get('cart') if cart_json is not None: cart_dict_cookie = json.loads(cart_json) else: cart_dict_cookie = {} # 从redis中获取购物车数据 redis_conn = get_redis_connection('default') cart_dict_redis = redis_conn.hgetall('cart_%s'%user.id) # 进行购物车商品数量合并:将cookie中购物车数量合并到redis中 for sku_id, count in cart_dict_cookie.items(): # 提示:因为redis中的键与值都是bytes类型,cookie中的sku_id是字符串类型 # 须要将cookie中的sku_id字符串转成bytes sku_id = sku_id.encode() if sku_id in cart_dict_redis: # 若是cookie中的购物车商品在redis中也有,就取出来累加到redis中 # 提示:redis中的count是bytes,cookie中的count是整数,没法求和,因此,转完数据类型在求和 origin_count = cart_dict_redis[sku_id] count += int(origin_count) # 若是cookie中的商品在redis中有,就累加count赋值。反之,直接赋值cookie中的count cart_dict_redis[sku_id] = count # 将合并后的redis数据,设置到redis中:redis_conn.hmset()不能传入空字典 if cart_dict_redis: redis_conn.hmset('cart_%s'%user.id, cart_dict_redis) # 获取next参数,用于判断登录界面是从哪里来的 next = request.GET.get('next') if next is None: # 跳转到首页 response = redirect(reverse('goods:index')) else: # 从哪儿来,回哪儿去 response = redirect(next) # 清除cookie response.delete_cookie('cart') return response
+
,增长购物车商品数量时,若是其中有一次数据传输失败,则商品数量出错{% extends 'base.html' %} {% block title %}每天生鲜-购物车{% endblock %} {% load staticfiles %} {% block search_bar %} <div class="search_bar clearfix"> <a href="{% url 'goods:index' %}" class="logo fl"><img src="{% static 'images/logo.png' %}"></a> <div class="sub_page_name fl">| 购物车</div> <div class="search_con fr"> <form action="/search/" method="get"> <input type="text" class="input_text fl" name="q" placeholder="搜索商品"> <input type="submit" class="input_btn fr" value="搜索"> </form> </div> </div> {% endblock %} {% block body %} <div class="total_count">所有商品<em>{{total_count}}</em>件</div> <ul class="cart_list_th clearfix"> <li class="col01">商品名称</li> <li class="col02">商品单位</li> <li class="col03">商品价格</li> <li class="col04">数量</li> <li class="col05">小计</li> <li class="col06">操做</li> </ul> <form method="post" action="#"> {% csrf_token %} {% for sku in skus %} <ul class="cart_list_td clearfix" sku_id="{{ sku.id }}"> <li class="col01"><input type="checkbox" name="sku_ids" value="{{ sku.id }}" checked></li> <li class="col02"><img src="{{ sku.default_image.url }}"></li> <li class="col03">{{ sku.name }}<br><em>{{ sku.price }}/{{ sku.unit}}</em></li> <li class="col04">{{ sku.unit }}</li> <li class="col05"><span>{{sku.price}}</span>元</li> <li class="col06"> <div class="num_add"> <a href="javascript:;" class="add fl">+</a> <input type="text" class="num_show fl" sku_id="{{ sku.id }}" value="{{sku.count}}"> <a href="javascript:;" class="minus fl">-</a> </div> </li> <li class="col07"><span>{{sku.amount}}</span>元</li> <li class="col08"><a href="javascript:;" class="del_btn">删除</a></li> </ul> {% endfor %} <ul class="settlements"> <li class="col01"><input type="checkbox" checked></li> <li class="col02">全选</li> <li class="col03">合计(不含运费):<span>¥</span><em id="total_amount">{{total_amount}}</em><br>共计<b id="total_count">{{total_count}}</b>件商品</li> <li class="col04"><a href="place_order.html">去结算</a></li> </ul> </form> {% endblock %} {% block bottom_files %} <script type="text/javascript" src="{% static 'js/jquery-1.12.2.js' %}"></script> <script type="text/javascript"> // 更新页面合计信息 function freshOrderCommitInfo() { var total_amount = 0; //总金额 var total_count = 0; // 总数量 $('.cart_list_td').find(':checked').parents('ul').each(function () { var sku_amount = $(this).children('li.col07').text(); // 商品的金额 var sku_count = $(this).find('.num_show').val(); // 商品的数量 total_count += parseInt(sku_count); total_amount += parseFloat(sku_amount); }); // 设置商品的总数和总价 $("#total_amount").text(total_amount.toFixed(2)); $("#total_count").text(total_count); } // 更新页面顶端所有商品数量 function freshTotalGoodsCount() { var total_count = 0; $('.cart_list_td').find(':checkbox').parents('ul').each(function () { var sku_count = $(this).find('.num_show').val(); total_count += parseInt(sku_count); }); $(".total_count>em").text(total_count); } // 更新后端购物车信息 function updateRemoteCartInfo(sku_id, sku_count, num_dom) { // 发送给后端的数据 var req = { sku_id: sku_id, count: sku_count, csrfmiddlewaretoken: "{{ csrf_token }}" }; $.post("/cart/update", req, function(data){ if (0 == data.code) { // 更新商品数量 $(num_dom).val(sku_count); // 更新商品金额信息 var sku_price = $(".cart_list_td[sku_id="+sku_id+"]").children('li.col05').children().text(); var sku_amount = parseFloat(sku_price) * sku_count; $(".cart_list_td[sku_id="+sku_id+"]").children('li.col07').children().text(sku_amount.toFixed(2)); // 更新顶部商品总数 freshTotalGoodsCount(); // 更新底部合计信息 freshOrderCommitInfo(); } else { alert(data.message); } }); } // 增长 $(".add").click(function(){ // 获取操做的商品id var sku_id = $(this).next().attr("sku_id"); // 获取加操做前的的数量 var sku_num = $(this).next().val(); // 进行数量加1 sku_num = parseInt(sku_num); sku_num += 1; // 显示商品数目的dom var num_dom = $(this).next(); // 更新购物车数量 updateRemoteCartInfo(sku_id, sku_num, num_dom); }); // 减小 $(".minus").click(function(){ // 获取操做的商品id var sku_id = $(this).prev().attr("sku_id"); // 获取加操做前的的数量 var sku_num = $(this).prev().val(); // 进行数量加1 sku_num = parseInt(sku_num); sku_num -= 1; if (sku_num < 1) sku_num = 1; // 更新页面显示数量 var num_dom = $(this).prev(); // 更新购物车数量 updateRemoteCartInfo(sku_id, sku_num, num_dom); }); var pre_sku_count = 0; $('.num_show').focus(function () { // 记录用户手动输入以前商品数目 pre_sku_count = $(this).val(); }); // 手动输入 $(".num_show").blur(function(){ var sku_id = $(this).attr("sku_id"); var sku_num = $(this).val(); // 若是输入的数据不合理,则将输入值设置为在手动输入前记录的商品数目 if (isNaN(sku_num) || sku_num.trim().length<=0 || parseInt(sku_num)<=0) { $(this).val(pre_sku_count); return; } sku_num = parseInt(sku_num); var num_dom = $(this); updateRemoteCartInfo(sku_id, sku_num, num_dom); }); // 删除 $(".del_btn").click(function(){ var sku_id = $(this).parents("ul").attr("sku_id"); var req = { sku_id: sku_id, csrfmiddlewaretoken: "{{ csrf_token }}" }; $.post('/cart/delete', req, function(data){ // window.reload() location.href="/cart/"; // 删除后,刷新页面 }); }); // 商品对应checkbox发生改变时,全选checkbox发生改变 $('.cart_list_td').find(':checkbox').change(function () { // 获取商品全部checkbox的数目 var all_len = $('.cart_list_td').find(':checkbox').length; // 获取选中商品的checkbox的数目 var checked_len = $('.cart_list_td').find(':checked').length; if (checked_len < all_len){ // 有商品没有被选中 $('.settlements').find(':checkbox').prop('checked', false) } else{ // 全部商品都被选中 $('.settlements').find(':checkbox').prop('checked', true) } freshOrderCommitInfo(); }); // 全选和全不选 $('.settlements').find(':checkbox').change(function () { // 1.获取当前checkbox的选中状态 var is_checked = $(this).prop('checked'); // 2.遍历并设置商品ul中checkbox的选中状态 $('.cart_list_td').find(':checkbox').each(function () { // 设置每个goods ul中checkbox的值 $(this).prop('checked', is_checked) }); freshOrderCommitInfo(); }); </script> {% endblock %}
# 更新购物车数据 url(r'^update$', views.UpdateCartView.as_view(), name='update'),
class UpdateCartView(View): """更新购物车数据:+ -""" def post(self,request): # 获取参数:sku_id, count # 校验参数all() # 判断商品是否存在 # 判断count是不是整数 # 判断库存 # 判断用户是否登录 # 若是用户登录,将修改的购物车数据存储到redis中 # 若是用户未登录,将修改的购物车数据存储到cookie中 # 响应结果 pass
class UpdateCartView(View): """更新购物车数据:+ - 编辑""" def post(self, request): # 获取参数:sku_id, count sku_id = request.POST.get('sku_di') count = request.POST.get('count') # 校验参数all() if not all([sku_id, count]): return JsonResponse({'code': 1, 'message': '参数不完整'}) # 判断商品是否存在 try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: return JsonResponse({'code': 2, 'message': '商品不存在'}) # 判断count是不是整数 try: count = int(count) except Exception: return JsonResponse({'code': 3, 'message': '数量有误'}) # 判断库存 if count > sku.stock: return JsonResponse({'code': 4, 'message': '库存不足'}) # 判断用户是否登录 if request.user.is_authenticated(): # 若是用户登录,将修改的购物车数据存储到redis中 redis_conn = get_redis_connection('default') user_id = request.user.id # 若是设计成幂等的,count就是最终要保存的商品的数量,不须要累加 redis_conn.hset('cart_%s'%user_id, sku_id, count) return JsonResponse({'code': 0, 'message': '添加购物车成功'}) else: # 若是用户未登录,将修改的购物车数据存储到cookie中 # 获取cookie中的购物车的json字符串 cart_json = request.COOKIES.get('cart') # 若是json字符串存在,将json字符串转成字典,由于用户可能历来没有添加过购物车 if cart_json is not None: cart_dict = json.loads(cart_json) else: cart_dict = {} # 若是设计成幂等的,count就是最终要保存的商品的数量,不须要累加 cart_dict[sku_id] = count # 将购物车字典转成json字符串格式 new_cart_json = json.dumps(cart_dict) # 响应结果 response = JsonResponse({'code': 0, 'message': '添加购物车成功'}) # 写入cookie response.set_cookie('cart', new_cart_json) return response
# 删除购物车数据 url(r'^delete$', views.DeleteCartView.as_view(), name='delete')
class DeleteCartView(View): """删除购物车数据""" def post(self, request): # 接收参数:sku_id # 校验参数:not,判断是否为空 # 判断用户是否登陆 # 若是用户登录,删除redis中购物车数据 # 若是用户未登录,删除cookie中购物车数据 pass
class DeleteCartView(View): """删除购物车数据""" def post(self, request): # 接收参数:sku_id sku_id = request.POST.get('sku_id') # 校验参数:not,判断是否为空 if not sku_id: return JsonResponse({'code': 1, 'message': '参数错误'}) # 判断用户是否登陆 if request.user.is_authenticated(): # 若是用户登录,删除redis中购物车数据 redis_conn= get_redis_connection('default') user_id = request.user.id # 商品不存在会直接忽略 redis_conn.hdel('cart_%s'%user_id, sku_id) else: # 若是用户未登录,删除cookie中购物车数据 cart_json = request.COOKIES.get('cart') if cart_json is not None: cart_dict = json.loads(cart_json) # 判断要删除的商品是否存在 if sku_id in cart_dict: # 字典删除key对应的value del cart_dict[sku_id] # 响应中从新写入cookie response = JsonResponse({'code': 0, 'message': '删除成功'}) response.set_cookie('cart', json.dumps(cart_dict)) return response # 当删除成功或者没有要删除的都提示用户成功 return JsonResponse({'code': 0, 'message': '删除成功'})
LoginRequiredMixin
LoginRequiredMixin
LoginRequiredMixin
不响应json数据,而是响应302的重定向request.user
获取关联的Addresssku_ids=sku_1&sku_ids=sku_2
sku_ids = request.POST.getlist('sku_ids')
# 确认订单 url(r'^place$', views.PlaceOrdereView.as_view(), name='place')
class PlaceOrdereView(LoginRequiredMixin, View): """订单确认页面""" def post(self, request): # 判断用户是否登录:LoginRequiredMixin # 获取参数:sku_ids, count # 校验sku_ids参数:not # 校验count参数:用于区分用户从哪儿进入订单确认页面 # 若是是从购物车页面过来 # 查询商品数据 # 商品的数量从redis中获取 # 若是是从详情页面过来 # 查询商品数据 # 商品的数量从request中获取,并try校验 # 判断库存:当即购买没有判断库存 # 查询用户地址信息 # 构造上下文 # 响应结果:html页面 pass
去结算
和当即购买
class PlaceOrdereView(LoginRequiredMixin, View): """订单确认页面""" def post(self, request): # 判断用户是否登录:LoginRequiredMixin # 获取参数:sku_ids, count sku_ids = request.POST.getlist('sku_ids') # 用户从详情过来时,才有count count = request.POST.get('count') pass
class PlaceOrdereView(LoginRequiredMixin, View): """订单确认页面""" def post(self, request): # 判断用户是否登录:LoginRequiredMixin # 获取参数:sku_ids, count sku_ids = request.POST.getlist('sku_ids') # 用户从详情过来时,才有count count = request.POST.get('count') # 校验sku_ids参数 if not sku_ids: # 若是sku_ids没有,就重定向购物车,重选 return redirect(reverse('cart:info')) # 查询商品数据 if count is None: # 若是是从购物车页面过来,商品的数量从redis中获取 # 遍历商品sku_ids else: # 若是是从详情页面过来,商品的数量从request中获取 # 遍历商品sku_ids pass
class PlaceOrdereView(LoginRequiredMixin, View): """订单确认页面""" def post(self, request): # 判断用户是否登录:LoginRequiredMixin # 获取参数:sku_ids, count sku_ids = request.POST.getlist('sku_ids') # 用户从详情过来时,才有count count = request.POST.get('count') # 校验参数 if not sku_ids: # 若是sku_ids没有,就重定向到购物车,重选 return redirect(reverse('cart:info')) # 定义临时容器 skus = [] total_count = 0 total_sku_amount = 0 trans_cost = 10 total_amount = 0 # 实付款 # 查询商品数据 if count is None: # 若是是从购物车页面过来,商品的数量从redis中获取 redis_conn = get_redis_connection('default') user_id = request.user.id cart_dict = redis_conn.hgetall('cart_%s'%user_id) # 遍历商品sku_ids for sku_id in sku_ids: try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 重定向到购物车 return redirect(reverse('cart:info')) # 取出每一个sku_id对应的商品数量 sku_count = cart_dict.get(sku_id.encode()) sku_count = int(sku_count) # 计算商品总金额 amount = sku.price * sku_count # 将商品数量和金额封装到sku对象 sku.count = sku_count sku.amount = amount skus.append(sku) # 金额和数量求和 total_count += sku_count total_sku_amount += amount else: # 若是是从详情页面过来,商品的数量从request中获取 # 遍历商品sku_ids:若是是从详情过来,sku_ids只有一个sku_id for sku_id in sku_ids: try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 重定向到购物车 return redirect(reverse('cart:info')) # 获取request中获得的count try: sku_count = int(count) except Exception: return redirect(reverse('goods:detail', args=sku_id)) # 判断库存:当即购买没有判断库存 if sku_count > sku.stock: return redirect(reverse('goods:detail', args=sku_id)) # 计算商品总金额 amount = sku.price * sku_count # 将商品数量和金额封装到sku对象 sku.count = sku_count sku.amount = amount skus.append(sku) # 金额和数量求和 total_count += sku_count total_sku_amount += amount # 实付款 total_amount = total_sku_amount + trans_cost # 用户地址信息 try: address = Address.objects.filter(user=request.user).latest('create_time') except Address.DoesNotExist: address = None # 模板会作判断,而后跳转到地址编辑页面 # 构造上下文 context = { 'skus':skus, 'total_count':total_count, 'total_sku_amount':total_sku_amount, 'trans_cost':trans_cost, 'total_amount':total_amount, 'address':address } # 响应结果:html页面 return render(request, 'place_order.html', context)
LoginRequiredMixin
引导到登录界面next参数
,将用户引导回来PlaceOrdereView
支持POST
请求,可是next参数
重定向回来的是GET
请求405
if next is None: response = redirect(reverse('goods:index')) else: if next == '/orders/place': response = redirect('/cart') else: response = redirect(next)
CommitOrderView
视图,主要逻辑是保存订单信息,并把成功、错误经过json传给前端页面# 订单提交 url(r'^commit$', views.CommitOrderView.as_view(), name='commit')
class CommitOrderView(View): """订单提交""" def post(self, request): pass
from functools import wraps def login_required_json(view_func): # 恢复view_func的名字和文档 @wraps(view_func) def wrapper(request, *args, **kwargs): # 若是用户未登陆,返回json数据 if not request.user.is_authenticated(): return JsonResponse({'code': 1, 'message': '用户未登陆'}) else: # 若是用户登录,进入到view_func中 return view_func(request, *args, **kwargs) return wrapper
class LoginRequiredJSONMixin(object): @classmethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) return login_required_json(view)
class CommitOrderView(LoginRequiredJSONMixin, View): """订单提交""" def post(self, request): pass
参数:web
商品数量参数的思考ajax
优化逻辑:点击当即购买将商品加入到购物车redis
class CommitOrderView(View): """订单提交""" def post(self, request): # 获取参数:user,address_id,pay_method,sku_ids,count # 校验参数:all([address_id, pay_method, sku_ids]) # 判断地址 # 判断支付方式 # 截取出sku_ids列表 # 遍历sku_ids # 循环取出sku,判断商品是否存在 # 获取商品数量,判断库存 (redis) # 减小sku库存 # 增长sku销量 # 保存订单商品数据OrderGoods(能执行到这里说明无异常) # 先建立商品订单信息 # 计算总数和总金额 # 修改订单信息里面的总数和总金额(OrderInfo) # 订单生成后删除购物车(hdel) # 响应结果 pass
# django提供的时间格式化工具 from django.utils import timezone # python提供的时间格式化工具 datetime 和 time # 相关方法 strftime : 将时间转字符串 strptime : 将字符串转时间 # 使用:20171222031955 timezone.now().strftime('%Y%m%d%H%M%S')
class CommitOrderView(LoginRequiredJSONMixin, View): """提交订单""" def post(self, request): # 获取参数:user,address_id,pay_method,sku_ids,count user = request.user address_id = request.POST.get('address_id') pay_method = request.POST.get('pay_method') sku_ids = request.POST.get('sku_ids') # 校验参数:all([address_id, sku_ids, pay_method]) if not all([address_id, sku_ids, pay_method]): return JsonResponse({'code': 2, 'message': '缺乏参数'}) # 判断地址 try: address = Address.objects.get(id=address_id) except Address.DoesNotExist: return JsonResponse({'code': 3, 'message': '地址不存在'}) # 判断支付方式 if pay_method not in OrderInfo.PAY_METHOD: return JsonResponse({'code': 4, 'message': '支付方式错误'}) # 建立redis连接对象,取出字典 redis_conn = get_redis_connection('default') cart_dict = redis_conn.hgetall('cart_%s'%user.id) # 判断商品是否存在:跟前端约定,sku_ids='1,2,3' sku_ids = sku_ids.split(',') # 定义临时容器 total_count = 0 total_amount = 0 # 手动生成order_id order_id = timezone.now().strftime('%Y%m%d%H%M%S')+str(user.id) # 在建立订单商品信息前,建立商品订单信息,(商品订单和订单商品时一对多的关系) order = OrderInfo.objects.create( order_id = order_id, user = user, address = address, total_amount = 0, trans_cost = 10, pay_method = pay_method ) # 遍历sku_ids, for sku_id in sku_ids: # 循环取出sku try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: return JsonResponse({'code': 5, 'message': '商品不存在'}) # 获取商品数量,判断库存 (redis) sku_count = cart_dict.get(sku_id.encode()) sku_count = int(sku_count) if sku_count > sku.stock: return JsonResponse({'code': 6, 'message': '库存不足'}) # 减小sku库存 sku.stock -= sku_count # 增长sku销量 sku.sales += sku_count sku.save() # 保存订单商品数据OrderGoods(能执行到这里说明无异常) OrderGoods.objects.create( order = order, sku = sku, count = sku_count, price = sku.price ) # 计算总数和总金额 total_count += sku_count total_amount += (sku_count * sku.price) # 修改订单信息里面的总数和总金额(OrderInfo) order.total_count = total_count order.total_amount = total_amount + 10 order.save() # 订单生成后删除购物车(hdel) redis_conn.hdel('cart_%s'%user.id, *sku_ids) # 响应结果 return JsonResponse({'code': 0, 'message': '下单成功'})
OrderInfo
和OrderGoods
保存数据时,若是出现异常,须要执行回滚,不要自动提交from django.db import transaction class TransactionAtomicMixin(object): """提供数据库事务功能""" @classmethod def as_view(cls, **initkwargs): view = super(TransactionAtomicMixin, cls).as_view(**initkwargs) return transaction.atomic(view)
当数据库操做结束,尚未异常时,才能提交事务
class CommitOrderView(LoginRequiredJSONMixin, TransactionAtomicMixin, View): """订单提交""" def post(self, request): # 获取参数:user,address_id,pay_method,sku_ids,count user = request.user address_id = request.POST.get('address_id') sku_ids = request.POST.get('sku_ids') # '1,2,3' pay_method = request.POST.get('pay_method') # 校验参数 if not all([address_id, sku_ids, pay_method]): return JsonResponse({'code': 2, 'message': '缺乏参数'}) # 判断地址 try: address = Address.objects.get(id=address_id) except Address.DoesNotExist: return JsonResponse({'code': 3, 'message': '地址不存在'}) # 判断支付方式 if pay_method not in OrderInfo.PAY_METHOD: return JsonResponse({'code': 4, 'message': '支付方式错误'}) # 建立redis链接对象 redis_conn = get_redis_connection('default') cart_dict = redis_conn.hgetall('cart_%s' % user.id) # 建立订单id:时间+user_id order_id = timezone.now().strftime('%Y%m%d%H%M%S')+str(user.id) # 在操做数据库前建立事务保存点 save_point = transaction.savepoint() try: # 先建立商品订单信息 order = OrderInfo.objects.create( order_id = order_id, user = user, address = address, total_amount = 0, trans_cost = 10, pay_method = pay_method, ) # 判断商品是否存在 sku_ids = sku_ids.split(',') # 定义临时容器 total_count = 0 total_amount = 0 # 遍历sku_ids,循环取出sku for sku_id in sku_ids: try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 5, 'message': '商品不存在'}) # 获取商品数量,判断库存 sku_count = cart_dict.get(sku_id.encode()) sku_count = int(sku_count) if sku_count > sku.stock: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 6, 'message': '库存不足'}) # 减小库存 sku.stock -= sku_count # 增长销量 sku.sales += sku_count sku.save() # 保存订单商品数据 OrderGoods.objects.create( order = order, sku = sku, count = sku_count, price = sku.price, ) # 计算总数和总金额 total_count += sku_count total_amount += (sku.price * sku_count) # 修改订单信息里面的总数和总金额 order.total_count = total_count order.total_amount = total_amount + 10 order.save() except Exception: # 出现任何异常都回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 7, 'message': '下单失败'}) # 没有异常,就手动提交 transaction.savepoint_commit(save_point) # 订单生成后删除购物车 redis_conn.hdel('cart_%s' % user.id, *sku_ids) # 响应结果 return JsonResponse({'code': 0, 'message': '订单建立成功'})
没有使用锁
# 减小sku库存 sku.stock -= sku_count # 增长sku销量 sku.sales += sku_count sku.save()
使用乐观锁
# 减小库存,增长销量 origin_stock = sku.stock new_stock = origin_stock - sku_count new_sales = sku.sales + sku_count # 更新库存和销量 result = GoodsSKU.objects.filter(id=sku_id,stock=origin_stock).update(stock=new_stock,sales=new_sales) if 0 == result: # 异常,回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 8, 'message': '下单失败'})
# 每一个订单三次下单机会 for i in range(3): pass
class CommitOrderView(LoginRequiredJSONMixin, TransactionAtomicMixin, View): """订单提交""" def post(self, request): # 获取参数:user,address_id,pay_method,sku_ids,count user = request.user address_id = request.POST.get('address_id') sku_ids = request.POST.get('sku_ids') # '1,2,3' pay_method = request.POST.get('pay_method') # 校验参数 if not all([address_id, sku_ids, pay_method]): return JsonResponse({'code': 2, 'message': '缺乏参数'}) # 判断地址 try: address = Address.objects.get(id=address_id) except Address.DoesNotExist: return JsonResponse({'code': 3, 'message': '地址不存在'}) # 判断支付方式 if pay_method not in OrderInfo.PAY_METHOD: return JsonResponse({'code': 4, 'message': '支付方式错误'}) # 建立redis链接对象 redis_conn = get_redis_connection('default') cart_dict = redis_conn.hgetall('cart_%s' % user.id) # 建立订单id:时间+user_id order_id = timezone.now().strftime('%Y%m%d%H%M%S')+str(user.id) # 在操做数据库前建立事务保存点 save_point = transaction.savepoint() try: # 先建立商品订单信息 order = OrderInfo.objects.create( order_id = order_id, user = user, address = address, total_amount = 0, trans_cost = 10, pay_method = pay_method, ) # 判断商品是否存在 sku_ids = sku_ids.split(',') # 定义临时容器 total_count = 0 total_amount = 0 # 遍历sku_ids,循环取出sku for sku_id in sku_ids: for i in range(3): try: sku = GoodsSKU.objects.get(id=sku_id) except GoodsSKU.DoesNotExist: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 5, 'message': '商品不存在'}) # 获取商品数量,判断库存 sku_count = cart_dict.get(sku_id.encode()) sku_count = int(sku_count) if sku_count > sku.stock: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 6, 'message': '库存不足'}) # 减小库存,增长销量 origin_stock = sku.stock new_stock = origin_stock - sku_count new_sales = sku.sales + sku_count # 更新库存和销量 result = GoodsSKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,sales=new_sales) if 0 == result and i < 2 : continue # 还有机会,继续从新下单 elif 0 == result and i == 2: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 8, 'message': '下单失败'}) # 保存订单商品数据 OrderGoods.objects.create( order = order, sku = sku, count = sku_count, price = sku.price, ) # 计算总数和总金额 total_count += sku_count total_amount += (sku.price * sku_count) # 下单成功,跳出循环 break # 修改订单信息里面的总数和总金额 order.total_count = total_count order.total_amount = total_amount + 10 order.save() except Exception: # 出现任何异常都回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 7, 'message': '下单失败'}) # 没有异常,就手动提交 transaction.savepoint_commit(save_point) # 订单生成后删除购物车 redis_conn.hdel('cart_%s' % user.id, *sku_ids) # 响应结果 return JsonResponse({'code': 0, 'message': '订单建立成功'})
place_order.html
当中'/orders/commit'
place_order.html
模板时,在上下文中传入sku_ids,
隔开的字符串
# 构造上下文 context = { 'skus':skus, 'total_count':total_count, 'total_sku_amount':total_sku_amount, 'trans_cost':trans_cost, 'total_amount':total_amount, 'address':address, 'sku_ids':','.join(sku_ids) }
# 获取商品数量,判断库存 (redis) sku_count = cart_dict.get(sku_id.encode()) sku_count = int(sku_count) if sku_count > sku.stock: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 6, 'message': '库存不足'}) import time time.sleep(10) origin_stock = sku.stock new_stock = origin_stock - sku_count new_sales = sku.sales + sku_count result = GoodsSKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales) if 0 == result and i < 2: continue elif 0 == result and i == 2: # 回滚 transaction.savepoint_rollback(save_point) return JsonResponse({'code': 8, 'message': '库存不足'}) # 保存订单商品数据OrderGoods(能执行到这里说明无异常) OrderGoods.objects.create( order=order, sku=sku, count=sku_count, price=sku.price )
# 订单信息页面 url(r'^(?P<page>\d+)$', views.UserOrdersView.as_view(), name='info')
class UserOrdersView(LoginRequiredMixin, View): """用户订单页面""" def get(self, request, page): """提供订单信息页面""" user = request.user # 查询全部订单 orders = user.orderinfo_set.all().order_by("-create_time") # 遍历全部订单 for order in orders: # 给订单动态绑定:订单状态 order.status_name = OrderInfo.ORDER_STATUS[order.status] # 给订单动态绑定:支付方式 order.pay_method_name = OrderInfo.PAY_METHODS[order.pay_method] order.skus = [] # 查询订单中全部商品 order_skus = order.ordergoods_set.all() # 遍历订单中全部商品 for order_sku in order_skus: sku = order_sku.sku sku.count = order_sku.count sku.amount = sku.price * sku.count order.skus.append(sku) # 分页 page = int(page) try: paginator = Paginator(orders, 2) page_orders = paginator.page(page) except EmptyPage: # 若是传入的页数不存在,就默认给第1页 page_orders = paginator.page(1) page = 1 # 页数 page_list = paginator.page_range context = { "orders": page_orders, "page": page, "page_list": page_list, } return render(request, "user_center_order.html", context)