对于做项目而言,最重要的是分析清楚自己负责模块的思路,确定思路后,把每一步实现的步骤确定后,根据步骤,去实现代码,测试。

购物车的逻辑:
    登录用户可以添加购物车,未登陆用户页可以添加到购物车
    登陆用户的保存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代码

添加购物车的功能已实现,查询后期再更新