# 項目的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)