路飞项目深科技相关表结构及购物车
# ######################## 深科技相关 ######################## class ArticleSource(models.Model): """文章来源""" name = models.CharField(max_length=64, unique=True) class Meta: verbose_name_plural = "16. 文章来源" def __str__(self): return self.name class Article(models.Model): """文章资讯""" title = models.CharField(max_length=255, unique=True, db_index=True, verbose_name="标题") source = models.ForeignKey("ArticleSource", verbose_name="来源") article_type_choices = ((0, '资讯'), (1, '视频')) article_type = models.SmallIntegerField(choices=article_type_choices, default=0) brief = models.TextField(max_length=512, verbose_name="摘要") head_img = models.CharField(max_length=255) content = models.TextField(verbose_name="文章正文") pub_date = models.DateTimeField(verbose_name="上架日期") offline_date = models.DateTimeField(verbose_name="下架日期") status_choices = ((0, '在线'), (1, '下线')) status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="状态") order = models.SmallIntegerField(default=0, verbose_name="权重", help_text="文章想置顶,可以把数字调大,不要超过1000") vid = models.CharField(max_length=128, verbose_name="视频VID", help_text="文章类型是视频, 则需要添加视频VID", blank=True, null=True) comment_num = models.SmallIntegerField(default=0, verbose_name="评论数") agree_num = models.SmallIntegerField(default=0, verbose_name="点赞数") view_num = models.SmallIntegerField(default=0, verbose_name="观看数") collect_num = models.SmallIntegerField(default=0, verbose_name="收藏数") # tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签") date = models.DateTimeField(auto_now_add=True, verbose_name="创建日期") position_choices = ((0, '信息流'), (1, 'banner大图'), (2, 'banner小图')) position = models.SmallIntegerField(choices=position_choices, default=0, verbose_name="位置") #comment = GenericRelation("Comment") class Meta: verbose_name_plural = "17. 文章" def __str__(self): return "%s-%s" % (self.source, self.title) class Collection(models.Model): """收藏""" content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') account = models.ForeignKey("Account") date = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('content_type', 'object_id', 'account') verbose_name_plural = "18. 通用收藏表" class Comment(models.Model): """通用的评论表""" content_type = models.ForeignKey(ContentType, blank=True, null=True, verbose_name="类型") object_id = models.PositiveIntegerField(blank=True, null=True) content_object = GenericForeignKey('content_type', 'object_id') p_node = models.ForeignKey("self", blank=True, null=True, verbose_name="父级评论") content = models.TextField(max_length=1024) account = models.ForeignKey("Account", verbose_name="会员名") disagree_number = models.IntegerField(default=0, verbose_name="踩") agree_number = models.IntegerField(default=0, verbose_name="赞同数") date = models.DateTimeField(auto_now_add=True) def __str__(self): return self.content class Meta: verbose_name_plural = "19. 通用评论表" class Account(models.Model): username = models.CharField("用户名", max_length=64, unique=True) password = models.CharField("密码", max_length=64) class UserAuthToken(models.Model): """ 用户Token表 """ user = models.OneToOneField(to="Account") token = models.CharField(max_length=64, unique=True)
路飞的深科技结构?
- -文章来源
- -文章详细
- -收藏
- -点赞
- -评论
- -用户
- -用户token
路飞购物车
加入购物车,保存到redis。
- 因为购物车只是一个暂时的状态,当结算完成的实收会删除购物车的内容.且购物车的操作可能比较频繁,因为客户会考虑的比较多
- 如果只用数据库的话,那么每次修改都对数据库进行修改,数据库的压力会比较大.
- 如果用redis+数据库,比如一天放到redis里,然后12点后存放到数据库.这个方案也是可以
- 但是如果存在数据库,那么就需要一个购物车的表结构.
- 而reids可以不用创建表结构,就能完成同样的事情,而且性能更高
路飞购物车字典是如何构造的?
{ # luffy_shopping_car_用户id_课程id luffy_shopping_car_6_1:{ 'title':'xxxxx', 'img':'xxx' 'prolicy':{ 10:{'name':'有效期1个月','price':123}, 11:{'name':'有效期1个月','price':123}, 12:{'name':'有效期1个月','price':123}, 'defalut_prolicy':10, }, }, luffy_shopping_car_6_2:{ ... }, luffy_shopping_car_6_3:{ ... } }
settings中配置redis
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://140.143.227.206:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100}, "PASSWORD": "1234", } } }
SHOPPING_CAR_KEY = "luffy_shopping_car_%s_%s"
url.py
url(r'^shoppingcar/$', shoppingcar.ShoppingCarViewSet.as_view()),
认证:
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)
视图,实现增删改查
购物车的实现思路
1.用户选择:课程 价格策略,提交 2.获取课程 价格策略进行合法校验(数据库) 3.数据获取,构造结构: { shopping_car_用户id_课程id:{ 'title':'', img:'xxx', policy:{ }, default:'' } } 4. 将数据以字典的形式保存到redis中. 修改: 1.用户选择:课程 价格策略,提交 2.获取课程 价格策略进行合法校验(redis查询) 3.更新 删除: 1.用户选择:课程 价格策略,提交 2.获取课程 价格策略进行合法校验(redis查询) 3.删除 查看:1.构造key_shopping_car_用户ID_* 2.scan_iter
POST请求:购物车中添加一条数据 请求体: { courseid:1, policy_id:10 } 后台: 检验当前课程是否有此价格策略,合法:将数据构造字典,再添加到redis
GET请求:查看自己购物车中的所有数据 获取当前登录用户ID,根据用户ID去redis的购物车中获取数据。 DELETE请求:删除购物车中的数据 请求体: { course_ids:[1,2] } PUT/PATCH请求:更新价格策略 请求体: { courseid:1, policy_id:13 }
class ShoppingCarViewSet(APIView): authentication_classes = [LuffyAuth,] conn = get_redis_connection("default") # 类下的全局 下面用加self def post(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. 获取专题课信息 course = models.Course.objects.get(id=course_id) # 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, } # 4. 判断用户提交的价格策略是否合法 if policy_id not in price_policy_dict: # 价格策略不合法 raise PricePolicyInvalid('价格策略不合法') # 5. 将购物信息添加到redis中 # self.conn # car_key = "luffy_shopping_car_%s_%s" 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") self.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 = str(request.data.get('policyid')) # 2. 拼接课程的key key = settings.SHOPPING_CAR_KEY %(request.auth.user_id,course_id,) 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')) if 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 = 1004 ret.error = "修改失败" return Response(ret.dict) def get(self,request, *args, **kwargs): """ 查看购物车中所有的商品 :param request: :param args: :param kwargs: :return: """ ret = BaseResponse() try: key_match = settings.SHOPPING_CAR_KEY %(request.auth.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 = 1002 ret.error = "获取失败" return Response(ret.dict)
I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我