前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >day100-Exception继承定义错误信息&结算接口&结算数据结构

day100-Exception继承定义错误信息&结算接口&结算数据结构

原创
作者头像
少年包青菜
修改2020-03-30 15:29:33
6620
修改2020-03-30 15:29:33
举报
文章被收录于专栏:Python 学习Python 学习

1.Exception的继承

代码语言:javascript
复制
# 自定义继承类继承 Exception
class MyException(Exception):
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg


# 自定义相应信息
class BaseResponse:
    def __init__(self):
        self.code = ''
        self.error = ''
        self.msg = ''

    @property
    def dict(self):
        return self.__dict__


# 实例化响应对象
my_res = BaseResponse()
try:
    if not 1:
        raise MyException(1000, 'test_my_exception')
    """其他代码"""
    """ll = int(s)"""
    """其他代码"""
    
# 这个对应的是 MyException 的错误
except MyException as e:
    my_res.code = e.code
    my_res.msg = e.msg
    
# 这个对应的是 try 对应的其他代码的未知错误
except Exception as e:
    my_res.msg = str(e)

print(my_res.dict)

2.接口

2.1models的代码,新加了 Coupon 和 CouponRecord

代码语言:javascript
复制
from django.db import models
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.contrib.contenttypes.models import ContentType

# Create your models here.
__all__ = ["Category", "Course", "CourseDetail", "Teacher",
           "DegreeCourse", "CourseChapter",
           "CourseSection", "PricePolicy",
           "OftenAskedQuestion", "Comment",
           "Account", "CourseOutline",
           "Coupon", "CouponRecord"]


# 首先上面有课程分类
class Category(models.Model):
    """课程分类表"""
    title = models.CharField(max_length=32, unique=True, verbose_name="课程的分类")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "01-课程分类表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 每一条课程分类下面有课程
class Course(models.Model):
    """课程表"""
    title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")

    course_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='课程的图片')
    # media/course/2018-11/xxx.png

    category = models.ForeignKey(to="Category", verbose_name="课程的分类")
    COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程"))
    course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES)
    degree_course = models.ForeignKey(to="DegreeCourse", blank=True, null=True, help_text="如果是学位课程,必须关联学位表")
    # course_type    degree_course_id
    #  0                null
    #  1                null
    #  2                2

    brief = models.CharField(verbose_name="课程简介", max_length=1024)
    level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
    level = models.SmallIntegerField(choices=level_choices, default=1)
    status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
    order = models.IntegerField(verbose_name="课程顺序", help_text="从上一个课程数字往后排, 建议中间空几个数字")
    study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人买课程,订单表加入数据的同时给这个字段+1")
    is_free = models.BooleanField(default=False)

    # order_details = GenericRelation("OrderDetail", related_query_name="course")
    # coupon = GenericRelation("Coupon")
    # 只用于反向查询不生成字段
    price_policy = GenericRelation("PricePolicy")
    often_ask_questions = GenericRelation("OftenAskedQuestion")
    course_comments = GenericRelation("Comment")

    def save(self, *args, **kwargs):
        if self.course_type == 2:
            if not self.degree_course:
                raise ValueError("学位课必须关联学位课程表")
        super(Course, self).save(*args, **kwargs)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "02-课程表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 每一条课程里面都有课程详情
class CourseDetail(models.Model):
    """课程详细表"""
    course = models.OneToOneField(to="Course")
    hours = models.IntegerField(verbose_name="课时")
    course_slogan = models.CharField(max_length=125, blank=True, null=True, verbose_name="课程口号")
    # 视频简介链接
    video_brief_link = models.CharField(max_length=255, blank=True, null=True)
    summary = models.TextField(max_length=2048, verbose_name="课程概述")
    why_study = models.TextField(verbose_name="为什么学习这门课程")
    service = 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)
    recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
    teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")

    def __str__(self):
        return self.course.title

    class Meta:
        verbose_name = "03-课程详细表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


class Teacher(models.Model):
    """讲师表"""
    name = models.CharField(max_length=32, verbose_name="讲师名字")
    brief = models.TextField(max_length=1024, verbose_name="讲师介绍")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "04-教师表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 只是一个单独的深度学习的title
class DegreeCourse(models.Model):
    """
    字段大体跟课程表相同,哪些不同根据业务逻辑去区分
    """
    title = models.CharField(max_length=32, verbose_name="学位课程名字")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "05-学位课程表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 课程章节表,课程有多个章节
class CourseChapter(models.Model):
    """课程章节表"""
    course = models.ForeignKey(to="Course", related_name="course_chapters")
    # 排序用的
    chapter = models.SmallIntegerField(default=1, verbose_name="第几章")
    title = models.CharField(max_length=32, verbose_name="课程章节名称")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "06-课程章节表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ("course", "chapter")


# 课时表,一章课程有多个课程
class CourseSection(models.Model):
    """课时表"""
    chapter = models.ForeignKey(to="CourseChapter", related_name="course_sections")
    title = models.CharField(max_length=32, verbose_name="课时")
    section_order = models.SmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
    section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
    free_trail = models.BooleanField("是否可试看", default=False)
    section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
    # 视频链接
    section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")

    def __str__(self):
        return "%s-%s" % (self.chapter, self.title)

    class Meta:
        verbose_name = "07-课程课时表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('chapter', 'section_link')


# 价格策略表
class PricePolicy(models.Model):
    """价格策略表"""
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    valid_period_choices = ((1, '1天'), (3, '3天'),
                            (7, '1周'), (14, '2周'),
                            (30, '1个月'),
                            (60, '2个月'),
                            (90, '3个月'),
                            (120, '4个月'),
                            (180, '6个月'), (210, '12个月'),
                            (540, '18个月'), (720, '24个月')
                            )
    valid_period = models.SmallIntegerField(choices=valid_period_choices)
    price = models.FloatField()

    def __str__(self):
        return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)

    class Meta:
        verbose_name = "08-价格策略表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ("content_type", 'object_id', "valid_period")


# 常见问题
class OftenAskedQuestion(models.Model):
    """常见问题"""
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    question = models.CharField(max_length=255)
    answer = models.TextField(max_length=1024)

    def __str__(self):
        return "%s-%s" % (self.content_object, self.question)

    class Meta:
        verbose_name = "09-常见问题表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('content_type', 'object_id', 'question')


# 用户评论表
class Comment(models.Model):
    """通用的评论表"""
    # 定位表
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    # 定位对象的id
    object_id = models.PositiveIntegerField(blank=True, null=True)
    # 定位对象
    content_object = GenericForeignKey('content_type', 'object_id')

    content = models.TextField(max_length=1024, verbose_name="评论内容")
    account = models.ForeignKey("Account", verbose_name="会员名")
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "10-评价表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 用户表
class Account(models.Model):
    username = models.CharField(max_length=32, verbose_name="用户姓名")
    pwd = models.CharField(max_length=128)

    create_token_time = models.DateTimeField(auto_now=True)

    token = models.UUIDField(null=True, blank=True)

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "11-用户表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


# 课程大纲,在课程详情里面
class CourseOutline(models.Model):
    """课程大纲"""
    course_detail = models.ForeignKey(to="CourseDetail", related_name="course_outline")
    title = models.CharField(max_length=128)
    order = models.PositiveSmallIntegerField(default=1)
    # 前端显示顺序

    content = models.TextField("内容", max_length=2048)

    def __str__(self):
        return "%s" % self.title

    class Meta:
        verbose_name = "12-课程大纲表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('course_detail', 'title')


#################################################################

class Coupon(models.Model):
    """优惠券生成规则"""
    name = models.CharField(max_length=64, verbose_name="活动名称")
    brief = models.TextField(blank=True, null=True, verbose_name="优惠券介绍")
    coupon_type_choices = ((0, '立减券'), (1, '满减券'), (2, '折扣券'))
    coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券类型")

    money_equivalent_value = models.IntegerField(verbose_name="等值货币", blank=True, null=True)
    off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只针对折扣券,例7.9折,写79", blank=True, null=True)
    minimum_consume = models.PositiveIntegerField("最低消费", default=0, help_text="仅在满减券时填写此字段")

    content_type = models.ForeignKey(ContentType, blank=True, null=True, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
    content_object = GenericForeignKey('content_type', 'object_id')

    quantity = models.PositiveIntegerField("数量(张)", default=1)
    open_date = models.DateField("优惠券领取开始时间")
    close_date = models.DateField("优惠券领取结束时间")
    valid_begin_date = models.DateTimeField(verbose_name="有效期开始时间", blank=True, null=True)
    valid_end_date = models.DateTimeField(verbose_name="有效结束时间", blank=True, null=True)
    coupon_valid_days = models.PositiveIntegerField(verbose_name="优惠券有效期(天)", blank=True, null=True,
                                                    help_text="自券被领时开始算起")
    date = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = "13-优惠券生成规则"

    def __str__(self):
        return "%s(%s)" % (self.get_coupon_type_display(), self.name)


class CouponRecord(models.Model):
    """优惠券发放、消费纪录"""
    coupon = models.ForeignKey("Coupon", on_delete=models.CASCADE)
    user = models.ForeignKey("Account", verbose_name="拥有者", on_delete=models.CASCADE)
    status_choices = ((0, '未使用'), (1, '已使用'), (2, '已过期'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    get_time = models.DateTimeField(verbose_name="领取时间", help_text="用户领取时间", null=True, blank=True)
    used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")

    class Meta:
        verbose_name_plural = "14-优惠券发放、消费纪录"

    def __str__(self):
        return '%s-%s-%s' % (self.user, self.coupon, self.get_status_display())

2.2结算接口,注意 # 时间属性必须转换格式才能被 json 序列化

代码语言:javascript
复制
class AccountView(APIView):
    authentication_classes = [authentication.MyAuthentication, ]

    @staticmethod
    def get_user_coupons_dict(request, course_id=None):
        print('id', course_id)
        coupon_dict = {}
        coupons_query_set = models.CouponRecord.objects.filter(
            # 首先指定表id
            coupon__content_type_id=10,
            # 指定课程id
            coupon__object_id=course_id,
            status=0,
            user=request.user,
            coupon__valid_begin_date__lt=now(),
            coupon__valid_end_date__gt=now(),
        )
        for coupon_record in coupons_query_set:
            coupon_dict[coupon_record.id] = {
                'name': coupon_record.coupon.name,
                'brief': coupon_record.coupon.brief,
                'coupon_type': coupon_record.coupon.get_coupon_type_display(),
                'money_equivalent_value': coupon_record.coupon.money_equivalent_value,
                'off_percent': coupon_record.coupon.off_percent,
                'minimum_consume': coupon_record.coupon.minimum_consume,
                # 注意时间属性只有被转换格式才可以被序列化
                'valid_begin_date': coupon_record.coupon.valid_begin_date.strftime('%Y-%m-%d'),
                'valid_end_date': coupon_record.coupon.valid_end_date.strftime('%Y-%m-%d'),
            }
        return coupon_dict

    @staticmethod
    def post(request):
        """本接口仅仅对购物车进行结算"""
        # {course_list: [XX, XX, ...]}
        test_dict = {}
        my_res = BaseResponse()
        try:
            """1.以最新的结算为准,清除Redis里面该用户原来的结算数据"""
            user_id = request.user.pk
            account_key = ACCOUNT_KEY.format(user_id, '*')
            delete_list = REDIS_CONN.keys(ACCOUNT_KEY)
            if delete_list:
                REDIS_CONN.delete(*account_key)

            """2.判断课程列表里的课程是否合法"""
            course_list = request.data.get('course_list', '')
            # 类型是否为列表
            if type(course_list) is not list:
                raise MyException(601, '参数类型非法!')
            # 是否存在相同课程
            course_list = [str(emp).strip() for emp in course_list]
            if len(course_list) != len(set(course_list)):
                raise MyException('602', '课程id不能相同!')
            # 是否存在非法课程
            for course_id in course_list:
                if not REDIS_CONN.exists(SHOPPING_CAR.format(user_id, course_id)):
                    raise MyException(602, '不存在相关课程!')

            for course_id in course_list:
                """3.拿到课程信息字典"""
                course_info = REDIS_CONN.get(SHOPPING_CAR.format(user_id, course_id))
                test_dict['course_info_{}'.format(course_id)] = json.loads(course_info)

                """3.5.根据课程id拿到课程优惠券字典"""
                test_dict[ACCOUNT_KEY.format(user_id, course_id)] = AccountView.get_user_coupons_dict(
                    request, course_id=course_id
                )

            """4.拿到该用户的公共优惠券"""
            global_coupons_dict = AccountView.get_user_coupons_dict(request)
            test_dict['global_coupons_dict'] = global_coupons_dict
            my_res.code = 600
            my_res.msg = 'SUCCESS'
            my_res.data = test_dict

            """5.写进 Redis """
            """ ... """

        except MyException as e:
            my_res.code = e.code
            my_res.msg = e.msg
        except Exception as e:
            my_res.code = -600
            my_res.msg = str(e)
        return Response(my_res.dict)

2.3结算数据结构

代码语言:javascript
复制
account = {
        # 结算接口数据结构
        "account_{}_{}": {
            "course_info": {
                "id": "XXX",
                "title": "XXX",
                "course_img": "XXX",
                "price_policy_dict": {
                    "valid_period": "XXX",
                    "price": "XXX"
                },
                "default_price_policy_id": "XXX"
            },
            # ...
            # ...

            "course_coupons": {
                "1": {
                    'course_id': "XXX",
                    'name': "XXX",
                    'coupon_type': "XXX",
                    'money_equivalent_value': "XXX",
                    'off_percent': "XXX",
                    'minimum_consume': "XXX",
                    'valid_begin_date': "XXX",
                    'valid_end_date': "XXX",
                },
                # ...
                # ...
            }
        },

        "global_coupon": {
            "1": {
                'name': "XXX",
                'coupon_type': "XXX",
                'money_equivalent_value': "XXX",
                'off_percent': "XXX",
                'minimum_consume': "XXX",
                'valid_begin_date': "XXX",
                'valid_end_date': "XXX",
            },
            # ...
            # ...
        }

    }

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Exception的继承
  • 2.接口
    • 2.1models的代码,新加了 Coupon 和 CouponRecord
      • 2.2结算接口,注意 # 时间属性必须转换格式才能被 json 序列化
        • 2.3结算数据结构
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档