登录合并购物车

在用户登录时,将cookie中的购物车数据合并到redis中,并清除cookie中的购物车数据。

普通登录和QQ登录都要合并,所以将合并逻辑放到公共函数里实现。

在carts/utils.py中创建merge_cart_cookie_to_redis方法

import pickle
import base64
from django_redis import get_redis_connection


def merge_cart_cookie_to_redis(request, user, response):
    """
    合并请求用户的购物车数据,将未登录保存在cookie里的保存到redis中
    遇到cookie与redis中出现相同的商品时以cookie数据为主,覆盖redis中的数据
    :param request: 用户的请求对象
    :param user: 当前登录的用户
    :param response: 响应对象,用于清楚购物车cookie
    :return:
    """
    # 获取cookie中的购物车
    cookie_cart = request.COOKIES.get('cart')
    if not cookie_cart:
        return response

    # 解析cookie购物车数据
    cookie_cart = pickle.loads(base64.b64decode(cookie_cart.encode()))

    # 用于保存向redis购物车商品数量hash添加数据的字典
    cart = {}

    # 记录redis勾选状态中应该增加的sku_id
    redis_cart_selected_add = []

    # 记录redis勾选状态中应该删除的sku_id
    redis_cart_selected_remove = []

    # 合并cookie购物车与redis购物车,保存到cart字典中
    for sku_id, count_selected_dict in cookie_cart.items():
        # 处理商品数量
        cart[sku_id] = count_selected_dict['count']

        if count_selected_dict['selected']:
            redis_cart_selected_add.append(sku_id)
        else:
            redis_cart_selected_remove.append(sku_id)

    if cart:
        redis_conn = get_redis_connection('cart')
        pl = redis_conn.pipeline()
        pl.hmset('cart_%s' % user.id, cart)
        if redis_cart_selected_add:
            pl.sadd('cart_selected_%s' % user.id, *redis_cart_selected_add)
        if redis_cart_selected_remove:
            pl.srem('cart_selected_%s' % user.id, *redis_cart_selected_remove)
        pl.execute()

    response.delete_cookie('cart')

    return response

修改登录视图

rest_framework_jwt提供的obtain_jwt_token视图,实际从rest_framework_jwt.views.ObtainJSONWebToken类视图而来,我们可以重写此类视图里的post方法来添加合并逻辑

from rest_framework_jwt.views import ObtainJSONWebToken

class UserAuthorizeView(ObtainJSONWebToken):
    """
    用户认证
    """
    def post(self, request, *args, **kwargs):
        # 调用父类的方法,获取drf jwt扩展默认的认证用户处理结果
        response = super().post(request, *args, **kwargs)

        # 仿照drf jwt扩展对于用户登录的认证方式,判断用户是否认证登录成功
        # 如果用户登录认证成功,则合并购物车
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            user = serializer.validated_data.get('user')
            response = merge_cart_cookie_to_redis(request, user, response)

        return response

修改路径users/urls.py

urlpatterns = [
    ...
    # url(r'^authorizations/$', obtain_jwt_token), 
    url(r'^authorizations/$', views.UserAuthorizeView.as_view()),
    ...
]

修改QQ登录视图

修改oauth/serializers.py中的序列化器

class OAuthQQUserSerializer(serializers.ModelSerializer):
    ...
    def create(self, validated_data):
        ...
        # 向视图对象中补充user对象属性,以便在视图中使用user
        self.context['view'].user = user

        return user

修改oauth/views.py中的视图

class OAuthQQUserView(CreateAPIView):
    """
    获取QQ用户对应的美多商城用户
    """
    serializer_class = OAuthQQUserSerializer

    def get(self, request):
        ...
        else:

            reponse = Response({
                'token': token,
                'username': user.username,
                'user_id': user.id
            })
            # 合并购物车
            response = merge_cart_cookie_to_redis(request, user, response)
            return response

    def post(self, request, *args, **kwargs):
        response = super().post(request, *args, **kwargs)

        # 合并购物车
        response = merge_cart_cookie_to_redis(request, self.user, response)
        return response