對於做項目而言,最重要的是分析清楚自己負責模塊的思路,確定思路后,把每一步實現的步驟確定后,根據步驟,去實現代碼,測試。
購物車的邏輯:
登錄用戶可以添加購物車,未登陸用戶頁可以添加到購物車
登陸用戶的保存user.id sku_id count selected 保存在redis中,以hash和set兩種方式保存
未登陸用戶保存sku_id count selectd 保存再cookie中
cart = {
sku_id:{count:5,selected:True},
sku_id:{count:1,selected:True},
}
后端接口設計:
請求方式:POST /cart/
1、項目中的settings.py中設置
# Application definition CORS_ALLOW_CREDENTIALS = True #允許攜帶cookie訪問
2、項目中的settings.py添加數據庫redis
CACHES = { "cart": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/4", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } }, }
3、創建子應用cart
在終端的虛擬環境下進入到工程中,執行以下命令
>>>(py3_django_38) python@ubuntu:~/Desktop/shopping_mall/mall/apps$ python ../manage.py startapp cart
4、在工程的settings.py中添加apps
INSTALLED_APPS = ['cart.apps.CartConfig'] #本質是讓工程加載子應用的配置,實質就是子應用配置的路徑,可以根據路徑查詢到子應用的配置
5、在cart/views.py中添加視圖
import pickle
import base64
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from cart.serializers import CartSerializer
class CartAPIView(APIView): ''' 因為我們APIView在我們調用http方法前會進行認證 我們的token過期或者偽造的化,會直接返回401 這個不符合業務邏輯 我們的業務邏輯應該是token過期或偽造的化應該認為是一個匿名用戶 匿名用戶的購物車數據可以放在cookie中 對於我們編程而言,應該能夠先進入http方法,等驗證用戶信息是,再驗證 ''' def perform_authentication(self, request): pass ''' 當用戶點擊添加購物車按鈕的時候 登陸用戶需要將token sku_id count 選中狀態提交給后端 未登陸用戶需要將 sku_id count 選中狀態提交給后端 后端:1、接收數據(sku_id count selected) 2、驗證數據 (驗證商品的id是否有對應的商品,商品的個數) 3、獲取數據 4、得到用戶信息 5、根據用戶的信息進行判斷 6、登陸用戶保存再redis中 6.1、鏈接redis 6.2、保存hash set 6.3返回響應 7、未登錄用戶 保存再cookie中 7.1 先讀取cookie信息 7.2 判斷是否有購物車信息 如果有 加密處理 如果沒有 7.3 判斷這個商品是否再cookie中 如果在,累加數據 如果不在則直接添加 7.4將購物車數據進行加密處理 7.5返回響應 ''' #添加購物車 def post(self,request): # #因為我們是在需要判斷的時候再去判斷用戶的信息 ,所以需要對用戶的信息進行異常捕獲 # try: # user = request.user # # except Exception as e: # user = None # pass #1、后端接收數據 data = request.data #2、驗證數據(對應id是否有商品,商品的個數) serializer = CartSerializer(data=data) serializer.is_valid(raise_exception=True) #獲取數據 sku_id = serializer.validated_data.get('sku_id') count = serializer.validated_data.get('count') selected = serializer.validated_data.get('selected') #4、得到用戶的信息 try: user = request.user except Exception as e: user = None #5、根據用戶的信息進行判斷 # request.user.is_authenticated if user is not None and user.is_authenticated: #user不為空,而且是認證用戶 #6、登陸用戶保存在redis中 #6.1鏈接redis redis_conn = get_redis_connection('cart') #6.2保存數據 #hash #具體的存儲方式需要查看文檔才能確定 # redis_conn.hset('cart_%s'%user.id,sku_id,count) # hash沒有進行累加操作 應該累加 # hincrby 累加操作 累加數據可以是正數頁可以是負數 # redis_conn.hincrby('cart_%s'%user.id,sku_id,count) ''' 管道 管道是基礎redis類的子類,他為在單個請求中向服務器緩沖多個命令提供技術支持 他們可以用於通過減少客戶端和服務器之間來回的tcp數據包數量來顯著提高命令組的性能 A、創建管道 pl = redis_conn.pipeline() B、將redis指令添加到管道中 pl.hincrby('cart_%s'%user.id,sku_id,count) C、執行管道 pl.execute() ''' pl = redis_conn.pipeline() pl.hincrby('cart_%s'%user.id,sku_id,count) #set if selected: # redis_conn.sadd('cart_selected_%s'%user.id,sku_id) pl.sadd('cart_selected_%s'%user.id,sku_id) pl.execute() #6.3返回數據 return Response(serializer.data) else: #7、未登錄用戶保存在cookie中 #7.1 先讀取cookie信息 cookie_str = request.COOKIES.get('cart') #7.2判斷是否有購物車信息 if cookie_str is not None: #如果有,則是加密數據 #7.2.1 將加密后的數據進行解碼 decode = base64.b64decode(cookie_str) #7.2.2 將二進制轉化為字典 cookie_cart = pickle.loads(decode) else: #如果沒有,則定義一個空字典 cookie_cart = {} #7.3判斷這個商品是否在cookie中 if sku_id in cookie_cart: #如果在 則累加, #先獲取之前的數據 original_count = cookie_cart[sku_id]['count'] count += original_count #如果不在,則直接添加 cookie_cart[sku_id] = { 'count':count, 'selected':selected } #將購物車進行加密處理 #7.4.1 將字典轉化為bytes類型 dumps = pickle.dumps(cookie_cart) #7.4.2 對bytes類型進行編碼 encode = base64.b64encode(dumps) #7.5返回響應 response = Response(serializer.data) #為啥要解碼呢 將二進制轉化為字符串 response.set_cookie('cart',encode.decode()) return response
6、添加序列化器
cart/serializers.py
from rest_framework import serializers class CartSerializer(serializers.Serializer): sku_id = serializers.IntegerField(label='sku_id', required=True, min_value=1) count = serializers.IntegerField(label='數量', required=True, min_value=1) selected = serializers.BooleanField(label='是否勾選', required=False, default=True) def validate(self, attrs): #判斷商品是否存在 sku_id = attrs['sku_id'] try: sku = SKU.objects.get(pk=sku_id) except SKU.DoesNotExist: raise serializers.ValidationError('商品不存在') #判斷庫存是否充足 count = attrs['count'] if sku.stock < count: raise serializers.ValidationError('庫存不足') return attrs
7、添加路由
7.1在工程的urls.py中添加
urlpatterns = [ url(r'^cart/',include('cart.urls')), ]
7.2在cart/urls.py中添加
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$',views.CartAPIView.as_view()), ]
8、添加html和js代碼
添加購物車的功能已實現,查詢后期再更新