购物车设计思路
0.先在redis测试
# Author:Jesi # Time : 2018/10/25 18:36 import redis import json conn=redis.Redis(host="47.99.191.149",port=6379,password=\'cyy520\') # conn.flushall() # #购买的第一商品 # data_dict={ # 11:{ # \'title\':\'21天从入门到放弃\', # \'src\':\'xxx.png\' # } # } # conn.hset(\'luffy_shopping_car\',\'11\',json.dumps(data_dict)) # car = conn.hget(\'luffy_shopping_car\',\'11\') # car_str=str(car,encoding=\'utf-8\') # car_dict=json.loads(car_str) # print(car_dict) # car_dict["12"]={ # \'title\':\'luffy_shopping_car\', # \'src\':\'xxx2.png\' # } # print(car_dict) # print(conn.keys()) # conn.flushall() #添加课程 # redis_key="luffy_shopping_car_%s_%s"%(6,12) # conn.hmset(redis_key,{\'title\':\'21天从入门到放弃\',\'src\':\'xxx.png\'}) #删除课程 # conn.delete(\'luffy_shopping_car_6_12\') #修改课程 # conn.hset(\'luffy_shopping_car_6_11\',\'src\',\'x1.png\') #查看所有课程 # print(conn.keys(\'luffy_shopping_car_6_*\')) # for item in conn.scan_iter(\'luffy_shopping_car_6_*\',count=10): # course=conn.hgetall(item) # # print(course) # for k,v in course.items(): # print(str(k,encoding=\'utf-8\'),str(v,encoding=\'utf-8\'))
正式开发购物车的接口:
因为购物车这种的有可能经常删除,修改等等,我们可以将这个东西放到redis中,速度更快,redis设置过期时间,如果长时间没有结算,那么应该把这个购物车清空。
添加URL
url(r\'shoppingcar/$\',shoppingcar.ShoppingCarViewSet.as_view({\'post\':\'create\'}))
在redis配置上django的redis
#redis配置 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://47.99.191.149:6379", #redis服务器地址 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100}, #最大连接池100 "PASSWORD": "xxxx", } } }
1.添加购物车接口
# Author:Jesi # Time : 2018/10/26 9:18 import json import redis from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet,ViewSetMixin from rest_framework.response import Response from django_redis import get_redis_connection #导入django_redis from utils.response import BaseResponse #导入状态信息基类 from api.views.auth.auth import LuffyAuth #导入认证组件 from api import models from django.core.exceptions import ObjectDoesNotExist from utils.exception import PricePolicyInvalid #自定制的价格策略非法异常 from django.conf import settings class ShoppingCarViewSet(ViewSetMixin,APIView): authentication_classes = [LuffyAuth,] conn = get_redis_connection(\'default\') # 拿到defalut这个redis连接池 def create(self,request,*args,**kwargs): \'\'\' 将课程添加到购物车 :param args: :param kwargs: :return: \'\'\' ret = BaseResponse() self.conn.set("name", "egon") try: #1.获取用户提交的课程ID和价格策略ID[这里注意int一下] course_id=int(request.data.get("courseid")) policy_id=int(request.data.get("policyid")) #2.获取专题课信息 course=models.Course.objects.filter(id=course_id).first() #3.获取该课程相关的所有价格策略 price_policy_list=course.price_policy.all() price_policy_dict={} #构建一个价格策略的字典。 for item in price_policy_list: price_policy_dict[item.id]={ "period":item.valid_period, "period_display":item.get_valid_period_display(), "price":item.price } print(price_policy_dict)
#{1: {\'period\': 3, \'period_display\': \'3天\', \'price\': 111.0}, 4: {\'period\': 30, \'period_display\': \'1个月\', \'price\': 399.0}} #4.判断用户提交的价格策略是否合法 if policy_id not in price_policy_dict: #价格策略不合法 raise PricePolicyInvalid("价格策略不合法") #5.将购物信息添加到redis中 car_key=settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) car_dict={ \'title\':course.name, \'img\':course.course_img, \'default_policy\':policy_id, \'policy\':json.dumps(price_policy_dict) #这里注意redis中需要将这里dumps一下才可以存入。 } conn=get_redis_connection("default") conn.hmset(car_key,car_dict) ret.data="添加成功!" except PricePolicyInvalid as e: #价格策略非法异常 ret.code=2001 ret.error=e.msg except ObjectDoesNotExist as e: #捕捉课程不存在的异常 ret.code = 2001 ret.error = "课程不存在" except Exception as e: ret.code=1001 ret.error="添加失败" return Response(ret.dict)
上面用到了一个认证的组件:
1.独立的认证组件,导入即可
LuffyAuth.py
from rest_framework.authentication import BaseAuthentication from api import models from rest_framework.exceptions import AuthenticationFailed class LuffyAuth(BaseAuthentication): def authenticate(self, request): """ 用户请求进行认证 :param request: :return: """ # http://wwwww...c0ovmadfasd/?token=adfasdfasdf token = request.query_params.get(\'token\') obj = models.UserAuthToken.objects.filter(token=token).first() if not obj: raise AuthenticationFailed({\'code\':1001,\'error\':\'认证失败\'}) return (obj.user.username,obj)
2.上一个用的封装好的返回信息的基类,导入通用。
response.py
class BaseResponse(object): \'\'\' 封装一个基础的字典 \'\'\' def __init__(self): self.code = 1000 self.data = None self.error = None @property def dict(self): return self.__dict__
3.exception.py
class PricePolicyInvalid(Exception): def __init__(self,msg): self.msg=msg
4.因为常用到这个redis的key,我们放到配置文件,业务中通过settings拿到直接用即可,不用一直写了。
settings.py
SHOPPING_CAR_KEY = "luffy_shopping_car_%s_%s"
最后在PY文件中测试一下,看一下redis到底存入了数据没有。
通过循环,拿到了购物车的数据,表示添加的接口开发完毕!
2.删除购物车
#删 def delete(self,request,*args,**kwargs): \'\'\' 购物车中删除课程 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: course_id_list=request.data.get("courseids") #获取到要删除的课程ID,是一个列表,可以删除多个课程 key_list=[settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) for course_id in course_id_list] #构建一个列表 self.conn.delete(*key_list) #使用*直接一起删除掉购物车内的多个选择要删除的课程 except Exception as e: ret.code=1002 ret.error="删除失败" return Response(ret.dict)
3.修改购物车
#改 def patch(self,request,*args,**kwargs): \'\'\' 修改课程的价格策略 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: #1.获取价格策略ID和课程ID course_id=int(request.data.get("courseid")) policy_id=int(request.data.get("policyid")) #2.拼接课程的key key=settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) print(key) if not self.conn.exists(key): ret.code= 1002 ret.error="购物车不存在此课程" return Response(ret.dict) #3.在redis中获取所有价格策略: policy_dict=json.loads(str(self.conn.hget(key,\'policy\'),encoding=\'utf-8\')) #这里需要loads回来并且做一个utf-8的转换 print(policy_dict) if str(policy_id) not in policy_dict: #可能出现用户私自修改价格策略,需要做一个判定 ret.code=1003 ret.error="价格策略不合法" return Response(ret.dict) #4.在购物车中修改该课程的默认价格策略 self.conn.hset(key,\'default_policy\',policy_id) #课程和价格策略全部合法后,进行一个修改。 ret.data="修改成功" except Exception as e: ret.code=1001 ret.error="课程修改失败" return Response(ret.dict)
4.查看购物车
#查 def get(self,request,*args,**kwargs): \'\'\' 查看购物车中所有的商品 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: current_user_id=request.auth.user_id key_match=settings.SHOPPING_CAR_KEY%(current_user_id,"*") #获取到当前登录用户所有的课程列表 course_list=[] for key in self.conn.scan_iter(key_match,count=10): #通过迭代依次取出 info={ "title" : self.conn.hget(key, "title").decode(\'utf-8\'), "img" : self.conn.hget(key, "img").decode(\'utf-8\'), "policy" : json.loads(self.conn.hget(key, "policy").decode(\'utf-8\')), "default_policy" : self.conn.hget(key, "default_policy").decode(\'utf-8\') } course_list.append(info) #做成一个列表套字典的形式。 ret.data=course_list except Exception as e: ret.code="1001" ret.error="获取失败" return Response(ret.dict)
获取到的结果显示如下:
{ "code": 1000, "data": [ { "title": "数学算数", "img": "451646", "policy": { "2": { "period": 3, "period_display": "3天", "price": 222 } }, "default_policy": "2" }, { "title": "语文阅读", "img": "25852585.jpg", "policy": { "1": { "period": 3, "period_display": "3天", "price": 111 }, "4": { "period": 30, "period_display": "1个月", "price": 399 } }, "default_policy": "4" } ], "error": null }
View Code
完整源码:
urls.py
from django.conf.urls import url from api.views.course import coursehost from api.views.user import account from api.views.course import newspapers from api.views.shopping import shoppingcar urlpatterns = [ url(r\'^login/$\', account.loginView.as_view()), url(r\'^course/$\', coursehost.CourseViewSet.as_view({"get": "list"})), url(r\'^course/(?P<pk>\d+)/$\', coursehost.CourseViewSet.as_view({"get": "retrieve"})), url(r\'^newspapers/\', newspapers.NewsPapers.as_view({"get": "list"})), url(r\'^newspapers/(?P<pk>\d+)/$\', newspapers.NewsPapers.as_view({"get": "retrieve"})), url(r\'^newspapers/(?P<pk>\d+)/agree/$\', newspapers.AgreeView.as_view({\'post\': \'post\'})), url(r\'shoppingcar/$\',shoppingcar.ShoppingCarViewSet.as_view())
View Code
shoppingcar.py
# Author:Jesi # Time : 2018/10/26 9:18 import json import redis from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet,ViewSetMixin from rest_framework.response import Response from django_redis import get_redis_connection from utils.response import BaseResponse from api.views.auth.auth import LuffyAuth from api import models from django.core.exceptions import ObjectDoesNotExist from utils.exception import PricePolicyInvalid from django.conf import settings class ShoppingCarViewSet(APIView): authentication_classes = [LuffyAuth,] conn = get_redis_connection(\'default\') # 拿到defalut这个redis连接池 #增 def post(self,request,*args,**kwargs): \'\'\' 将课程添加到购物车 :param args: :param kwargs: :return: \'\'\' ret = BaseResponse() self.conn.set("name", "egon") try: #1.获取用户提交的课程ID和价格策略ID[这里注意int一下] course_id=int(request.data.get("courseid")) policy_id=int(request.data.get("policyid")) #2.获取专题课信息 course=models.Course.objects.filter(id=course_id).first() #3.获取该课程相关的所有价格策略 price_policy_list=course.price_policy.all() price_policy_dict={} for item in price_policy_list: price_policy_dict[item.id]={ "period":item.valid_period, "period_display":item.get_valid_period_display(), "price":item.price } print(price_policy_dict) #4.判断用户提交的价格策略是否合法 if policy_id not in price_policy_dict: #价格策略不合法 raise PricePolicyInvalid("价格策略不合法") #5.将购物信息添加到redis中 car_key=settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) car_dict={ \'title\':course.name, \'img\':course.course_img, \'default_policy\':policy_id, \'policy\':json.dumps(price_policy_dict) } conn=get_redis_connection("default") conn.hmset(car_key,car_dict) ret.data="添加成功!" except PricePolicyInvalid as e: ret.code=2001 ret.error=e.msg except ObjectDoesNotExist as e: #捕捉课程不存在的异常 ret.code = 2001 ret.error = "课程不存在" except Exception as e: ret.code=1001 ret.error="添加失败" return Response(ret.dict) #删 def delete(self,request,*args,**kwargs): \'\'\' 购物车中删除课程 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: course_id_list=request.data.get("courseids") key_list=[settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) for course_id in course_id_list] self.conn.delete(*key_list) except Exception as e: ret.code=1002 ret.error="删除失败" return Response(ret.dict) #改 def patch(self,request,*args,**kwargs): \'\'\' 修改课程的价格策略 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: #1.获取价格策略ID和课程ID course_id=int(request.data.get("courseid")) policy_id=int(request.data.get("policyid")) #2.拼接课程的key key=settings.SHOPPING_CAR_KEY%(request.auth.user_id,course_id) print(key) if not self.conn.exists(key): ret.code= 1002 ret.error="购物车不存在此课程" return Response(ret.dict) #3.在redis中获取所有价格策略: policy_dict=json.loads(str(self.conn.hget(key,\'policy\'),encoding=\'utf-8\')) print(policy_dict) if str(policy_id) not in policy_dict: ret.code=1003 ret.error="价格策略不合法" return Response(ret.dict) #4.在购物车中修改该课程的默认价格策略 self.conn.hset(key,\'default_policy\',policy_id) ret.data="修改成功" except Exception as e: ret.code=1001 ret.error="课程修改失败" return Response(ret.dict) #查 def get(self,request,*args,**kwargs): \'\'\' 查看购物车中所有的商品 :param request: :param args: :param kwargs: :return: \'\'\' ret=BaseResponse() try: current_user_id=request.auth.user_id key_match=settings.SHOPPING_CAR_KEY%(current_user_id,"*") course_list=[] for key in self.conn.scan_iter(key_match,count=10): info={ "title" : self.conn.hget(key, "title").decode(\'utf-8\'), "img" : self.conn.hget(key, "img").decode(\'utf-8\'), "policy" : json.loads(self.conn.hget(key, "policy").decode(\'utf-8\')), "default_policy" : self.conn.hget(key, "default_policy").decode(\'utf-8\') } course_list.append(info) ret.data=course_list except Exception as e: ret.code="1001" ret.error="获取失败" return Response(ret.dict)
View Code