加入购物车实现
一、购物车逻辑
把价格策略+课程id存入redis,传入token进行认证,检验课程是否存在,
价格策略是否合适,也可以存在数据库,我们是存在redis里的,
为什么选择存在redis?
- 临时状态(之后购物车是需要删除的),这是小公司,为了节省空间,
可以用redis定时删除
- 价格策略有可能经常修改
使用redis主要就是避免对数据库进行重复操作,我们的redis买的是阿里云16G的服务
用户发送POST请求,创建购物车中的一条商品:
token
课程ID
价格策略ID
展示购物车页面发送:GET请求
获取redis中的所有课程
删除课程:DELETE
修改课程:PATCH
#用POstman运行请求测试
二、代码实现
url.py
urlpatterns = [
url(r'^shopping_car/$', shopping_car.ShoppingCarView.as_view()),
]
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.core.exceptions import ObjectDoesNotExist
from api import models
from api.utils.auth.api_view import AuthAPIView
from api.utils.exception import PricePolicyDoesNotExist
from pool import POOL
import json
from django.conf import settings
import redis
CONN = redis.Redis(connection_pool=POOL)
class ShoppingCarView(AuthAPIView,APIView):
def get(self,request,*args,**kwargs):
"""
查看购物车
:param request:
:param args:
:param kwargs:
:return:
"""
course = CONN.hget(settings.LUFFY_SHOPPING_CAR,request.user.id)
course_dict = json.loads(course.decode('utf-8'))
return Response(course_dict)
def post(self,request,*args,**kwargs):
"""
获取课程ID和价格策略ID,放入redis
:param request:
:param args:
:param kwargs:
:return:
"""
ret = {'code':1000,'msg':None}
try:
course_id = request.data.get('course_id')
price_policy_id = request.data.get('price_policy_id')
# 1. 获取课程
course_obj = models.Course.objects.get(id=course_id)
# 2. 获取当前课程的所有价格策略: id, 有效期,价格
price_policy_list = []
flag = False
price_policy_objs = course_obj.price_policy.all()
for item in price_policy_objs:
if item.id == price_policy_id:
flag = True
price_policy_list.append({'id':item.id, 'valid_period':item.get_valid_period_display(),'price':item.price})
if not flag:
raise PricePolicyDoesNotExist()
# 3. 课程和价格策略均没有问题,将课程和价格策略放到redis中
# 课程id,课程图片地址,课程标题,所有价格策略,默认价格策略
course_dict = {
'id':course_obj.id,
'img':course_obj.course_img,
'title':course_obj.name,
'price_policy_list':price_policy_list,
'default_policy_id':price_policy_id
}
# a. 获取当前用户购物车中的课程 car = {1: {,,,}, 2:{....}}
# b. car[course_obj.id] = course_dict
# c. conn.hset('luffy_shopping_car',request.user.id,car)
nothing = CONN.hget(settings.LUFFY_SHOPPING_CAR,request.user.id)
if not nothing:
data = {course_obj.id: course_dict}
else:
data = json.loads(nothing.decode('utf-8'))
data[course_obj.id] = course_dict
CONN.hset(settings.LUFFY_SHOPPING_CAR,request.user.id, json.dumps(data))
except ObjectDoesNotExist as e:
ret['code'] = 1001
ret['msg'] = "课程不存在"
except PricePolicyDoesNotExist as e:
ret['code'] = 1002
ret['msg'] = "价格策略不存在"
except Exception as e:
ret['code'] = 1003
ret['msg'] = "添加购物车异常"
return Response(ret)
def delete(self, request, *args, **kwargs):
res = {
"state": 10000,
"data": None,
"msg": None
}
course_id = request.data.get("course_id")
try:
cart = json.loads(CONN.hget(settings.SHOPPING_CART_KEY, request.user.id).decode("utf-8"))
cart.pop(str(course_id))
CONN.hset(settings.SHOPPING_CART_KEY, request.user.id, json.dumps(cart))
res["data"] = cart
except AttributeError:
# 用户第一次打开购物车,但是第一次打开购物车不可能走到这一步
res["state"] = 40000
res["msg"] = "非法操作,请检查数据"
except KeyError:
# 购物车已空或者删除不存在的商品,正常流程不会走到这一步
res["state"] = 40000
res["msg"] = "非法操作,请检查数据"
return JsonResponse(res)
def patch(self, request, *args, **kwargs):
# 局部更新与post功能重复,建议直接发post请求
res = ResData(msg="局部更新与post功能重复,请直接发post请求")
return JsonResponse(res)
def options(self, request, *args, **kwargs):
return JsonResponse({
"state": 10000,
"data": None,
"msg": None
})
三、认证
可以通过继承来做
views.py
from api.utils.auth.auth_view import AuthForView
AuthForView
from api.utils.auth.auth_token import LuffyCityTokenAuth
class AuthForView(object):
authentication_classes = [LuffyCityTokenAuth, ]
LuffyCityTokenAuth
import datetime
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from api import models
class LuffyCityTokenAuth(BaseAuthentication):
keyword = "token"
model = models.UserAuthToken
valid_period = 86400000 # 86400000毫秒=24小时
# valid_period = 100000 # 86400000毫秒=24小时
res = {
"state": 40000,
"data": {
"back_url": None,
# "auth_url": None
},
"msg": None
}
def authenticate(self, request):
self.res["data"]["back_url"] = request.path_info
token = request.query_params.get(self.keyword, None)
if not token:
self.res["msg"] = "请登录后访问"
raise AuthenticationFailed(self.res)
auth = self.model.objects.filter(token=token).first()
if not auth:
self.res["msg"] = "认证失败,请重新登录!"
raise AuthenticationFailed(self.res)
token_exist_period = self.get_token_exist_period(auth)
if token_exist_period > self.valid_period:
self.res["msg"] = "认证已过期,请重新登录!"
raise AuthenticationFailed(self.res)
return auth.user, auth
def get_token_exist_period(self, auth):
now = datetime.datetime.now()
return now.timestamp() - auth.created.timestamp()
越是困难的事越要立即去做,这样收益才会最大!!!
浙公网安备 33010602011771号