• django-luffycity-购物车接口


    一  基本功能

    -添加购物车
      -详见代码
    -修改课程价格策略
      -put或者patch
    {"course_id": "1", "policy_id": "1"}
    -查看购物车
    -删除购物车数据
    -购物车数据放在哪?
      -放到redis中,不需要创建mysql的表来存储数据了

    二  实现代码

    2.1相关表单建立

    from django.db import models
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.contenttypes.fields import GenericForeignKey
    
    from django.contrib.contenttypes.fields import GenericRelation
    # Create your models here.
    
    # class CourseType(models.Model):
    
    
    class UserInfo(models.Model):
        name = models.CharField(max_length=64)
        pwd = models.CharField(max_length=32)
    
    
    class Token(models.Model):
        user = models.OneToOneField(to=UserInfo)
        token = models.CharField(max_length=64)
    
    
    class Category(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=64)
    class Course(models.Model):
        """专题课程"""
        # unique=True 唯一性约束
    
    
        name = models.CharField(max_length=128, unique=True)
        course_img = models.CharField(max_length=255)
        brief = models.TextField(verbose_name="课程概述", max_length=2048)
    
        level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
        # 默认值为1 ,中级
        level = models.SmallIntegerField(choices=level_choices, default=1)
        pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
        period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=7)
        # help_text 在admin中显示的帮助信息
        order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排")
    
        status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
        price_policy = GenericRelation("PricePolicy")
        category = models.ForeignKey(to='Category',to_field='nid',null=True)
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name_plural = "专题课"
    
    
    class CourseDetail(models.Model):
        """课程详情页内容"""
        course = models.OneToOneField("Course", on_delete=models.CASCADE)
        hours = models.IntegerField("课时")
        # 课程的标语 口号
        course_slogan = models.CharField(max_length=125, blank=True, null=True)
        # video_brief_link = models.CharField(verbose_name='课程介绍', max_length=255, blank=True, null=True)
        # why_study = models.TextField(verbose_name="为什么学习这门课程")
        # what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")
        # career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")
        # prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
        # 推荐课程
        # related_name 基于对象的反向查询,用于替换表名小写_set
        recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
        teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
    
        def __str__(self):
            return "%s" % self.course
    
        class Meta:
            verbose_name_plural = "课程详细"
    
    
    
    class PricePolicy(models.Model):
        """价格与有课程效期表"""
        content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)  # 关联course or degree_course
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
    
        # course = models.ForeignKey("Course")
        valid_period_choices = ((1, '1天'), (3, '3天'),
                                (7, '1周'), (14, '2周'),
                                (30, '1个月'),
                                (60, '2个月'),
                                (90, '3个月'),
                                (180, '6个月'), (210, '12个月'),
                                (540, '18个月'), (720, '24个月'),
                                )
        valid_period = models.SmallIntegerField(choices=valid_period_choices)
        price = models.FloatField()
        class Meta:
            unique_together = ("content_type", 'object_id', "valid_period")
            verbose_name_plural = "价格策略"
    
        def __str__(self):
            return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
    
    class Teacher(models.Model):
        """讲师、导师表"""
        name = models.CharField(max_length=32)
        image = models.CharField(max_length=128)
        brief = models.TextField(max_length=1024)
    
        def __str__(self):
            return self.name
    
        class Meta:
    
            verbose_name_plural = "讲师"

    2.2自定义response与Exception信息

    class MyResponse():
        def __init__(self):
            self.status = 100
            self.msg = None
    
        @property
        def get_dic(self):
            return self.__dict__
    
    
    
    class CommonException(Exception):
        def __init__(self,status,msg):
            self.status =status
            self.msg = msg

    2.3登录认证组件

    from rest_framework.authentication import BaseAuthentication
    from api import models
    from rest_framework.exceptions import AuthenticationFailed
    
    
    class LoginAuth(BaseAuthentication):
        def authenticate(self, request):
            token = request.GET.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            if ret:
                # 有值说明认证通过,返回两个值
                return ret.user, ret
            else:
                raise AuthenticationFailed('认证失败,没有登录')

    2.4views

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models
    
    from api.utils.commonUtils import MyResponse
    from rest_framework.viewsets import ViewSetMixin
    from django.core.exceptions import ObjectDoesNotExist
    from django.conf import settings
    from api.utils.MyAuth import LoginAuth
    from api.utils.commonUtils import CommonException
    from django_redis import get_redis_connection
    import json
    
    
    # 需要登录之后才能操作,写一个认证组件
    class ShoppingCart(APIView):
        authentication_classes = [LoginAuth]
        conn = get_redis_connection()
    
        def post(self, request, *args, **kwargs):
            response = MyResponse()
            # 课程id,价格策略id
            # {"course_id": "1", "policy_id": "1"}
            # 放到redis中key值 shoppingcart_userid_courseid
            # 0 取出课程id,价格策略id
            course_id = str(request.data.get('course_id'))
            policy_id = str(request.data.get('policy_id'))
            # 1 校验课程是否合法
            try:
                course = models.Course.objects.get(pk=course_id)
                # 2 获取所有价格策略(通过课程拿出所有价格策略)
                policy_price_all = course.price_policy.all()
                # 3 从redis中取出当前登录用户的购物车
                shopping_byte = self.conn.get('shoppingcart_%s' % request.user.pk)
                if shopping_byte:
                    shopping_cart = json.loads(shopping_byte)
                else:
                    shopping_cart = {}
                #     循环构造出价格策略大字典
                policy = {}
                for policy_price in policy_price_all:
                    '''
                    {
                    "period":3,
                    "period_display":"3天",
                    "price":200
                    },
                    '''
                    policy_one = {
                        'period': policy_price.pk,
                        'period_display': policy_price.get_valid_period_display(),
                        'price': policy_price.price
                    }
                    policy[str(policy_price.pk)] = policy_one
                #     判断价格策略是否合法,不再字典中,就不合法
                if policy_id not in policy:
                    # 不合法
                    raise CommonException(102, '价格策略不合法,你不是人')
                # 判断传入的课程id是否在购物车中
                if course_id in shopping_cart:
                    # 更新一下默认价格策略
                    shopping_cart[course_id]['default_policy'] = policy_id
                    response.msg = '更新成功'
                else:
                    shopping_course = {
                        'title': course.name,
                        'img': course.course_img,
                        'default_policy': policy_id,
                        'policy': policy
                    }
    
                    # 添加到购物车
                    shopping_cart[course_id] = shopping_course
                    response.msg = '添加成功'
                #     写入redis
                self.conn.set('shoppingcart_%s' % request.user.pk, json.dumps(shopping_cart))
    
            except ObjectDoesNotExist as e:
                response.status = 101
                response.msg = '该课程不存在,你可能是爬虫'
            except CommonException as e:
                response.status = e.status
                response.msg = e.msg
            except Exception as e:
                response.status = 400
                response.msg = '未知错误'
                print(str(e))
            return Response(response.get_dic)
    
        def put(self,request,*args,**kwargs):
            response=MyResponse()
            # 0 取出课程id,价格策略id
            course_id = str(request.data.get('course_id'))
            policy_id = str(request.data.get('policy_id'))
            try:
                shopping_byte = self.conn.get('shoppingcart_%s' % request.user.pk)
                if shopping_byte:
                    shopping_cart = json.loads(shopping_byte)
                else:
                    shopping_cart = {}
                if course_id not in shopping_cart:
                    raise CommonException(102,'要修改的课程不存在')
                course_detail=shopping_cart.get(course_id)
                if policy_id not in course_detail['policy']:
                    raise CommonException(103, '价格策略不合法')
                course_detail['default_policy']=policy_id
                response.msg='修改成功'
                self.conn.set('shoppingcart_%s' % request.user.pk, json.dumps(shopping_cart))
    
            except ObjectDoesNotExist as e:
                response.status = 101
                response.msg = '该课程不存在,你可能是爬虫'
            except CommonException as e:
                response.status = e.status
                response.msg = e.msg
            except Exception as e:
                response.status = 400
                response.msg = '未知错误'
                print(str(e))
            return Response(response.get_dic)
    
        def get(self,request,*args,**kwargs):
            response=MyResponse()
            try:
                shopping_byte = self.conn.get('shoppingcart_%s' % request.user.pk)
                if shopping_byte:
                    shopping_cart = json.loads(shopping_byte)
                else:
                    shopping_cart = {}
                response.data=shopping_cart
    
            except Exception as e:
                response.status = 400
                response.msg = '未知错误'
                print(str(e))
            return Response(response.get_dic)
    
        def delete(self, request, *args, **kwargs):
            response=MyResponse()
            course_id=request.data.get('course_id')
            try:
                shopping_byte = self.conn.get('shoppingcart_%s' % request.user.pk)
                if shopping_byte:
                    shopping_cart = json.loads(shopping_byte)
                else:
                    shopping_cart = {}
                shopping_cart.pop(course_id,None)
                self.conn.set('shoppingcart_%s' % request.user.pk, json.dumps(shopping_cart))
            except Exception as e:
                response.status = 400
                response.msg = '未知错误'
                print(str(e))
            return Response(response.get_dic)

    2.5redis配置

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "CONNECTION_POOL_KWARGS": {"max_connections": 1000}
                # "PASSWORD": "123",
            }
        }
    }
  • 相关阅读:
    读书笔记之理想设计的特征
    一些javascript 变量声明的 疑惑
    LINQ 使用方法
    Google MySQL tool releases
    读书笔记之设计的层次
    EF之数据库连接问题The specified named connection is either not found in the configuration, not intended to be used with the Ent
    转载 什么是闭包
    javascript面向对象起步
    Tips
    数据结构在游戏中的应用
  • 原文地址:https://www.cnblogs.com/zhaijihai/p/10192586.html
Copyright © 2020-2023  润新知