zoukankan      html  css  js  c++  java
  • 关于redis缓存购物车及结算中心

    models.py

    from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    from django.contrib.contenttypes.models import ContentType
    from django.db.models import Q
    from django.db import models
    
    
    # ########################### 1.课程相关 ################################
    class CourseCategory(models.Model):
        """课程大类, e.g 前端  后端..."""
        name = models.CharField(max_length=64, unique=True)
    
        def __str__(self):
            return "%s" % self.name
    
        class Meta:
            verbose_name_plural = "01.课程大类"
    
    
    class CourseSubCategory(models.Model):
        """课程子类, e.g python linux """
        category = models.ForeignKey("CourseCategory")
        name = models.CharField(max_length=64, unique=True)
    
        def __str__(self):
            return "%s" % self.name
    
        class Meta:
            verbose_name_plural = "02.课程子类"
    
    
    class DegreeCourse(models.Model):
        """学位课程"""
        name = models.CharField(max_length=128, unique=True)
        course_img = models.CharField(max_length=255, verbose_name="缩略图")
        brief = models.TextField(verbose_name="学位课程简介", )
        total_scholarship = models.PositiveIntegerField(verbose_name="总奖学金(贝里)", default=40000)
        mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本课程的导师辅导费用(贝里)", default=15000)
        period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=150)  # 为了计算学位奖学金
        prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
        teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
        # 用于GenericForeignKey反向查询, 不会生成表字段,切勿删除
        coupon = GenericRelation("Coupon")
        # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
        degreecourse_price_policy = GenericRelation("PricePolicy")
        # 查询常见问题
        asked_question = GenericRelation("OftenAskedQuestion")
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name_plural = "03.学位课"
    
    
    class Teacher(models.Model):
        """讲师、导师表"""
        name = models.CharField(max_length=32)
        role_choices = ((0, '讲师'), (1, '导师'))
        role = models.SmallIntegerField(choices=role_choices, default=0)
        title = models.CharField(max_length=64, verbose_name="职位、职称")
        signature = models.CharField(max_length=255, help_text="导师签名", blank=True, null=True)
        image = models.CharField(max_length=128)
        brief = models.TextField(max_length=1024)
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name_plural = "04.导师或讲师"
    
    
    class Scholarship(models.Model):
        """学位课程奖学金"""
        degree_course = models.ForeignKey("DegreeCourse")
        time_percent = models.PositiveSmallIntegerField(verbose_name="奖励档位(时间百分比)", help_text="只填百分值,如80,代表80%")
        value = models.PositiveIntegerField(verbose_name="奖学金数额")
    
        def __str__(self):
            return "%s:%s" % (self.degree_course, self.value)
    
        class Meta:
            verbose_name_plural = "05.学位课奖学金"
    
    
    class Course(models.Model):
        """专题课程 OR 学位课模块"""
        name = models.CharField(max_length=128, unique=True) # Python基础
        course_img = models.CharField(max_length=255)
        sub_category = models.ForeignKey("CourseSubCategory") #
        course_type_choices = ((0, '付费'), (1, 'VIP专享'), (2, '学位课程'))
        course_type = models.SmallIntegerField(choices=course_type_choices)
        degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是学位课程,此处关联学位表")
        brief = models.TextField(verbose_name="课程(模块)概述", max_length=2048)
        level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
        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)
        order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排")
        attachment_path = models.CharField(max_length=128, verbose_name="课件路径", blank=True, null=True)
        status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        template_id = models.SmallIntegerField("前端模板id", default=1)
        # 如果是专题课时,获取相关优惠券
        coupon = GenericRelation("Coupon")
        # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
        price_policy = GenericRelation("PricePolicy")
        # 查询常见问题
        asked_question = GenericRelation("OftenAskedQuestion")
    
        class Meta:
            verbose_name_plural = "06.专题课或学位课模块"
    
    
    class CourseDetail(models.Model):
        """课程详情页内容"""
        course = models.OneToOneField("Course")
        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)
        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 = "07.课程或学位模块详细"
    
    
    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:
            unique_together = ('content_type', 'object_id', 'question')
            verbose_name_plural = "08. 常见问题"
    
    
    class CourseOutline(models.Model):
        """课程大纲"""
        course_detail = models.ForeignKey("CourseDetail")
        # 前端显示顺序
        order = models.PositiveSmallIntegerField(default=1)
        title = models.CharField(max_length=128)
        content = models.TextField("内容", max_length=2048)
    
        def __str__(self):
            return "%s" % self.title
    
        class Meta:
            unique_together = ('course_detail', 'title')
            verbose_name_plural = "09. 课程大纲"
    
    
    class CourseChapter(models.Model):
        """课程章节"""
        course = models.ForeignKey("Course", related_name='coursechapters')
        chapter = models.SmallIntegerField(verbose_name="第几章", default=1)
        name = models.CharField(max_length=128)
        summary = models.TextField(verbose_name="章节介绍", blank=True, null=True)
        pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)
    
        class Meta:
            unique_together = ("course", 'chapter')
            verbose_name_plural = "10. 课程章节"
    
        def __str__(self):
            return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)
    
    
    class CourseSection(models.Model):
        """课时目录"""
        chapter = models.ForeignKey("CourseChapter", related_name='coursesections')
        name = models.CharField(max_length=128)
        order = models.PositiveSmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
        section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
        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")
        video_time = models.CharField(verbose_name="视频时长", blank=True, null=True, max_length=32)  # 仅在前端展示使用
        pub_date = models.DateTimeField(verbose_name="发布时间", auto_now_add=True)
        free_trail = models.BooleanField("是否可试看", default=False)
    
        class Meta:
            unique_together = ('chapter', 'section_link')
            verbose_name_plural = "11. 课时"
    
        def __str__(self):
            return "%s-%s" % (self.chapter, self.name)
    
    
    class Homework(models.Model):
        chapter = models.ForeignKey("CourseChapter")
        title = models.CharField(max_length=128, verbose_name="作业题目")
        order = models.PositiveSmallIntegerField("作业顺序", help_text="同一课程的每个作业之前的order值间隔1-2个数")
        homework_type_choices = ((0, '作业'), (1, '模块通关考核'))
        homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)
        requirement = models.TextField(max_length=1024, verbose_name="作业需求")
        threshold = models.TextField(max_length=1024, verbose_name="踩分点")
        recommend_period = models.PositiveSmallIntegerField("推荐完成周期(天)", default=7)
        scholarship_value = models.PositiveSmallIntegerField("为该作业分配的奖学金(贝里)")
        note = models.TextField(blank=True, null=True)
        enabled = models.BooleanField(default=True, help_text="本作业如果后期不需要了,不想让学员看到,可以设置为False")
    
        class Meta:
            unique_together = ("chapter", "title")
            verbose_name_plural = "12. 章节作业"
    
        def __str__(self):
            return "%s - %s" % (self.chapter, self.title)
    
    
    class CourseReview(models.Model):
        """课程评价"""
        enrolled_course = models.OneToOneField("EnrolledCourse")
        about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
        about_video = models.FloatField(default=0, verbose_name="内容实用")
        about_course = models.FloatField(default=0, verbose_name="课程内容通俗易懂")
        review = models.TextField(max_length=1024, 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, verbose_name="评价日期")
        is_recommend = models.BooleanField("热评推荐", default=False)
        hide = models.BooleanField("不在前端页面显示此条评价", default=False)
    
        def __str__(self):
            return "%s-%s" % (self.enrolled_course.course, self.review)
    
        class Meta:
            verbose_name_plural = "13. 课程评价(购买课程后才能评价)"
    
    
    class DegreeCourseReview(models.Model):
        """学位课程评价
        为了以后可以定制单独的评价内容,所以不与普通课程的评价混在一起,单独建表
        """
        enrolled_course = models.ForeignKey("EnrolledDegreeCourse")
        course = models.ForeignKey("Course", verbose_name="评价学位模块", blank=True, null=True,
                                   help_text="不填写即代表评价整个学位课程", limit_choices_to={'course_type': 2})
        about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
        about_video = models.FloatField(default=0, verbose_name="视频质量")
        about_course = models.FloatField(default=0, verbose_name="课程")
        review = models.TextField(max_length=1024, 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, verbose_name="评价日期")
        is_recommend = models.BooleanField("热评推荐", default=False)
        hide = models.BooleanField("不在前端页面显示此条评价", default=False)
    
        def __str__(self):
            return "%s-%s" % (self.enrolled_course, self.review)
    
        class Meta:
            verbose_name_plural = "14. 学位课评价(购买课程后才能评价)"
    
    
    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个月'),
                                (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 = "15. 价格策略"
    
        def __str__(self):
            return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
    
    
    # ########################### 2. 深科技相关 ################################
    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="收藏数")
        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="位置")
    
        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. 通用评论表"
    
    
    # ########################### 3. 用户相关 ################################
    class Account(models.Model):
        username = models.CharField("用户名", max_length=64, unique=True)
        password = models.CharField("密码", max_length=64)
        uid = models.CharField(max_length=64, unique=True, help_text='微信用户绑定和CC视频统计')  # 与第3方交互用户信息时,用这个uid,以避免泄露敏感用户信息
        openid = models.CharField(max_length=128, blank=True, null=True)
        # 贝里余额
        balance = models.PositiveIntegerField(default=0, verbose_name="可提现和使用余额")
    
    
    class UserAuthToken(models.Model):
        """
        用户Token表
        """
        user = models.OneToOneField(to="Account")
        token = models.CharField(max_length=64, unique=True)
    
    
    # ########################### 4. 奖惩相关 ################################
    class ScoreRule(models.Model):
        """积分规则"""
        score_rule_choices = (
            (0, '未按时交作业'),
            (1, '未及时批改作业'),
            (2, '作业成绩'),
            (3, '未在规定时间内对学员进行跟进'),
            (4, '未在规定时间内回复学员问题'),
            (5, '收到学员投诉'),
            (6, '导师相关'),
            (7, '学位奖学金'),
        )
        rule = models.SmallIntegerField(choices=score_rule_choices, verbose_name="积分规则")
        score_type_choices = ((0, '奖励'), (1, '惩罚'), (2, '初始分配'))
        score_type = models.SmallIntegerField(choices=score_type_choices, verbose_name="奖惩", default=0)
        score = models.IntegerField(help_text="扣分数与贝里相等,若为0则代表规则的值可以从别处取得")
        # maturity_days = models.IntegerField("成熟周期", help_text="自纪录创建时开始计算")
        memo = models.TextField(blank=True, null=True)
    
        def __str__(self):
            return "%s-%s:%s" % (self.get_rule_display(), self.get_score_type_display(), self.score)
    
        class Meta:
            unique_together = ('rule', 'score_type')
            verbose_name_plural = "29. 奖惩规则"
    
    
    class ScoreRecord(models.Model):
        """积分奖惩记录"""
        content_type = models.ForeignKey(ContentType, blank=True, null=True)
        object_id = models.PositiveIntegerField(blank=True, null=True)
        content_object = GenericForeignKey('content_type', 'object_id')
        degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, verbose_name="关联学位课程")
        score_rule = models.ForeignKey("ScoreRule", verbose_name="关联规则")
        account = models.ForeignKey("Account", verbose_name="被执行人")
        score = models.IntegerField(verbose_name="金额(贝里)")   # 这里单独有一个字段存积分而不是从score_rule里引用的原因是考虑到如果引用的话, # 一旦score_rule里的积分有变更,那么所有用户的历史积分也会被影响
        received_score = models.IntegerField("实际到账金额贝里)", help_text="仅奖励用", default=0)
        balance = models.PositiveIntegerField(verbose_name="奖金余额(贝里)")
        maturity_date = models.DateField("成熟日期(可提现日期)")
        applied = models.BooleanField(default=False, help_text="奖赏纪录是否已被执行", verbose_name="是否已被执行")
        applied_date = models.DateTimeField(blank=True, null=True, verbose_name="事件生效日期")
        date = models.DateTimeField(auto_now_add=True, verbose_name="事件触发日期")
        memo = models.TextField(blank=True, null=True)
    
        def __str__(self):
            return "%s-%s - %s - %s 奖金余额:%s" % (self.id, self.score_rule, self.account, self.score, self.balance)
    
        class Meta:
            verbose_name_plural = "30. 奖惩记录"
    
    
    # ########################### 5. 支付相关 ################################
    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="等值货币")
        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)
        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.DateField(verbose_name="有效期开始时间", blank=True, null=True)
        valid_end_date = models.DateField(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 = "31. 优惠券生成记录"
    
        def __str__(self):
            return "%s(%s)" % (self.get_coupon_type_display(), self.name)
    
        def save(self, *args, **kwargs):
            if not self.coupon_valid_days or (self.valid_begin_date and self.valid_end_date):
                if self.valid_begin_date and self.valid_end_date:
                    if self.valid_end_date <= self.valid_begin_date:
                        raise ValueError("valid_end_date 有效期结束日期必须晚于 valid_begin_date ")
                if self.coupon_valid_days == 0:
                    raise ValueError("coupon_valid_days 有效期不能为0")
            if self.close_date < self.open_date:
                raise ValueError("close_date 优惠券领取结束时间必须晚于 open_date优惠券领取开始时间 ")
    
            super(Coupon, self).save(*args, **kwargs)
    
    
    class CouponRecord(models.Model):
        """优惠券发放、消费纪录"""
        coupon = models.ForeignKey("Coupon")
        number = models.CharField(max_length=64, unique=True)
        account = models.ForeignKey("Account", verbose_name="拥有者")
        status_choices = ((0, '未使用'), (1, '已使用'), (2, '已过期'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        get_time = models.DateTimeField(verbose_name="领取时间", help_text="用户领取时间")
        used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")
    
        class Meta:
            verbose_name_plural = "32. 用户优惠券"
    
        def __str__(self):
            return '%s-%s-%s' % (self.account, self.number, self.status)
    
    
    class CourseSchedule(models.Model):
        """课程进度计划表,针对学位课程,每开通一个模块,就为这个学员生成这个模块的推荐学习计划表,后面的奖惩均按此表进行"""
        study_record = models.ForeignKey("StudyRecord")
        homework = models.ForeignKey("Homework")
        recommend_date = models.DateField("推荐交作业日期")
    
        def __str__(self):
            return "%s - %s - %s " % (self.study_record, self.homework, self.recommend_date)
    
        class Meta:
            unique_together = ('study_record', 'homework')
            verbose_name_plural = "33. 课程模块计划表(学位课)"
    
    
    class EnrolledCourse(models.Model):
        """已报名课程,不包括学位课程"""
        account = models.ForeignKey("Account")
        course = models.ForeignKey("Course", limit_choices_to=~Q(course_type=2))
        enrolled_date = models.DateTimeField(auto_now_add=True)
        valid_begin_date = models.DateField(verbose_name="有效期开始自")
        valid_end_date = models.DateField(verbose_name="有效期结束至")
        status_choices = ((0, '已开通'), (1, '已过期'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        order_detail = models.OneToOneField("OrderDetail")  # 使订单购买后支持 课程评价
    
        def __str__(self):
            return "%s:%s" % (self.account, self.course)
    
        class Meta:
            verbose_name_plural = "34. 报名专题课"
    
    
    class DegreeRegistrationForm(models.Model):
        """学位课程报名表"""
        enrolled_degree = models.OneToOneField("EnrolledDegreeCourse")
        current_company = models.CharField(max_length=64, )
        current_position = models.CharField(max_length=64, )
        current_salary = models.IntegerField()
        work_experience_choices = ((0, "应届生"),
                                   (1, "1年"),
                                   (2, "2年"),
                                   (3, "3年"),
                                   (4, "4年"),
                                   (5, "5年"),
                                   (6, "6年"),
                                   (7, "7年"),
                                   (8, "8年"),
                                   (9, "9年"),
                                   (10, "10年"),
                                   (11, "超过10年"),
                                   )
        work_experience = models.IntegerField()
        open_module = models.BooleanField("是否开通第1模块", default=True)
        stu_specified_mentor = models.CharField("学员自行指定的导师名", max_length=32, blank=True, null=True)
        study_plan_choices = ((0, "1-2小时/天"),
                              (1, "2-3小时/天"),
                              (2, "3-5小时/天"),
                              (3, "5小时+/天"),
                              )
        study_plan = models.SmallIntegerField(choices=study_plan_choices, default=1)
        why_take_this_course = models.TextField("报此课程原因", max_length=1024)
        why_choose_us = models.TextField("为何选路飞", max_length=1024)
        your_expectation = models.TextField("你的期待", max_length=1024)
        memo = models.CharField(max_length=255, blank=True, null=True)
    
        class Meta:
            verbose_name_plural = "35. 报名表(学位课)"
    
        def __str__(self):
            return "%s" % self.enrolled_degree
    
    
    class EnrolledDegreeCourse(models.Model):
        """已报名的学位课程"""
        account = models.ForeignKey("Account")
        degree_course = models.ForeignKey("DegreeCourse")
        enrolled_date = models.DateTimeField(auto_now_add=True)
        valid_begin_date = models.DateField(verbose_name="有效期开始自", blank=True, null=True)  # 开通第一个模块时,再添加课程有效期,2年
        valid_end_date = models.DateField(verbose_name="有效期结束至", blank=True, null=True)
        status_choices = (
            (0, '在学中'),
            (1, '休学中'),
            (2, '已毕业'),
            (3, '超时结业'),
            (4, '未开始'),
            # (3, '其它'),
        )
        study_status = models.SmallIntegerField(choices=status_choices, default=0)
        mentor = models.ForeignKey("Account", verbose_name="导师", related_name='my_students',
                                   blank=True, null=True, limit_choices_to={'role': 1})
        mentor_fee_balance = models.PositiveIntegerField("导师费用余额", help_text="这个学员的导师费用,每有惩罚,需在此字段同时扣除")
        order_detail = models.OneToOneField("OrderDetail")  # 使订单购买后支持填写报名表
    
        def __str__(self):
            return "%s:%s" % (self.account, self.degree_course)
    
        class Meta:
            unique_together = ('account', 'degree_course')
            verbose_name_plural = "36. 报名学位课"
    
    
    class Order(models.Model):
        """订单"""
        payment_type_choices = ((0, '微信'), (1, '支付宝'), (2, '优惠码'), (3, '贝里'))
        payment_type = models.SmallIntegerField(choices=payment_type_choices)
        payment_number = models.CharField(max_length=128, verbose_name="支付第3方订单号", null=True, blank=True)
        order_number = models.CharField(max_length=128, verbose_name="订单号", unique=True)  # 考虑到订单合并支付的问题
        account = models.ForeignKey("Account")
        actual_amount = models.FloatField(verbose_name="实付金额")
        status_choices = ((0, '交易成功'), (1, '待支付'), (2, '退费申请中'), (3, '已退费'), (4, '主动取消'), (5, '超时取消'))
        status = models.SmallIntegerField(choices=status_choices, verbose_name="状态")
        date = models.DateTimeField(auto_now_add=True, verbose_name="订单生成时间")
        pay_time = models.DateTimeField(blank=True, null=True, verbose_name="付款时间")
        cancel_time = models.DateTimeField(blank=True, null=True, verbose_name="订单取消时间")
    
        class Meta:
            verbose_name_plural = "37. 订单表"
    
        def __str__(self):
            return "%s" % self.order_number
    
    
    class OrderDetail(models.Model):
        """订单详情"""
        order = models.ForeignKey("Order")
        content_type = models.ForeignKey(ContentType)  # 可关联普通课程或学位
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
        original_price = models.FloatField("课程原价")
        price = models.FloatField("折后价格")
        content = models.CharField(max_length=255, blank=True, null=True)  #
        valid_period_display = models.CharField("有效期显示", max_length=32)  # 在订单页显示
        valid_period = models.PositiveIntegerField("有效期(days)")  # 课程有效期
        memo = models.CharField(max_length=255, blank=True, null=True)
    
        def __str__(self):
            return "%s - %s - %s" % (self.order, self.content_type, self.price)
    
        class Meta:
            verbose_name_plural = "38. 订单详细"
            unique_together = ("order", 'content_type', 'object_id')
    
    
    class StudyRecord(models.Model):
        """学位课程的模块学习进度,报名学位课程后,每个模块会立刻生成一条学习纪录"""
        enrolled_degree_course = models.ForeignKey("EnrolledDegreeCourse")
        course_module = models.ForeignKey("Course", verbose_name="学位模块", limit_choices_to={'course_type': 2})
        open_date = models.DateField(blank=True, null=True, verbose_name="开通日期")
        end_date = models.DateField(blank=True, null=True, verbose_name="完成日期")
        status_choices = ((2, '在学'), (1, '未开通'), (0, '已完成'))
        status = models.SmallIntegerField(choices=status_choices, default=1)
    
        class Meta:
            verbose_name_plural = "39. 学习记录表(报名学位课程后,每个模块会立刻生成一条学习纪录)"
            unique_together = ('enrolled_degree_course', 'course_module')
    
        def __str__(self):
            return '%s-%s' % (self.enrolled_degree_course, self.course_module)
    
        def save(self, *args, **kwargs):
            if self.course_module.degree_course_id != self.enrolled_degree_course.degree_course_id:
                raise ValueError("学员要开通的模块必须与其报名的学位课程一致!")
    
            super(StudyRecord, self).save(*args, **kwargs)
    
    
    class TransactionRecord(models.Model):
        """贝里交易纪录"""
        account = models.ForeignKey("Account")
        amount = models.IntegerField("金额")
        balance = models.IntegerField("账户余额")
        transaction_type_choices = ((0, '收入'), (1, '支出'), (2, '退款'), (3, "提现"))  # 2 为了处理 订单过期未支付时,锁定期贝里的回退
        transaction_type = models.SmallIntegerField(choices=transaction_type_choices)
        content_type = models.ForeignKey(ContentType, blank=True, null=True)
        object_id = models.PositiveIntegerField(blank=True, null=True, verbose_name="关联对象")
        content_object = GenericForeignKey('content_type', 'object_id')
        transaction_number = models.CharField(unique=True, verbose_name="流水号", max_length=128)
        date = models.DateTimeField(auto_now_add=True)
        memo = models.CharField(max_length=128, blank=True, null=True)
    
        class Meta:
            verbose_name_plural = "40. 贝里交易记录"
    
        def __str__(self):
            return "%s" % self.transaction_number
    
    
    class HomeworkRecord(models.Model):
        """学员作业记录及成绩"""
        homework = models.ForeignKey("Homework")
        student = models.ForeignKey("EnrolledDegreeCourse", verbose_name="学生")
        score_choices = ((100, 'A+'),
                         (90, 'A'),
                         (85, 'B+'),
                         (80, 'B'),
                         (70, 'B-'),
                         (60, 'C+'),
                         (50, 'C'),
                         (40, 'C-'),
                         (-1, 'D'),
                         (0, 'N/A'),
                         (-100, 'COPY'),
                         )
        score = models.SmallIntegerField(verbose_name="分数", choices=score_choices, null=True, blank=True)
        mentor = models.ForeignKey("Account", related_name="my_stu_homework_record", limit_choices_to={'role': 1},
                                   verbose_name="导师")
        mentor_comment = models.TextField(verbose_name="导师批注", blank=True, null=True)  # 导师
        status_choice = (
            (0, '待批改'),
            (1, '已通过'),
            (2, '不合格'),
        )
        status = models.SmallIntegerField(verbose_name='作业状态', choices=status_choice, default=0)
        submit_num = models.SmallIntegerField(verbose_name='提交次数', default=0)
        correct_date = models.DateTimeField('备注日期', blank=True, null=True)
        note = models.TextField(blank=True, null=True)
        date = models.DateTimeField("作业提交日期", auto_now_add=True)
        check_date = models.DateTimeField("批改日期", null=True, blank=True)
        update_time = models.DateTimeField(auto_now=True, verbose_name="提交日期")
        reward_choice = ((0, '新提交'),
                         (1, '按时提交'),
                         (2, '未按时提交'),
                         (3, '成绩已奖励'),
                         (4, '成绩已处罚'),
                         (5, '未作按时检测'),
                         )
        reward_status = models.SmallIntegerField(verbose_name='作业记录奖惩状态', default=0)
    
        def __str__(self):
            return "%s %s" % (self.homework, self.student)
    
        class Meta:
            verbose_name_plural = "41. 作业"
            unique_together = ("homework", "student")
    
    
    class StuFollowUpRecord(models.Model):
        """学员跟进记录"""
        enrolled_degree_course = models.ForeignKey("EnrolledDegreeCourse", verbose_name="学生")
        mentor = models.ForeignKey("Account", related_name='mentor', limit_choices_to={'role': 1}, verbose_name="导师")
        followup_tool_choices = ((0, 'QQ'), (1, '微信'), (2, '电话'), (3, '系统通知'))
        followup_tool = models.SmallIntegerField(choices=followup_tool_choices, default=1)
        record = models.TextField(verbose_name="跟进记录")
        attachment_path = models.CharField(max_length=128, blank=True, null=True, verbose_name="附件路径", help_text="跟进记录的截图等")
        date = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = "42. 学员跟进记录"
    
        def __str__(self):
            return "%s --%s --%s" % (self.enrolled_degree_course, self.record, self.date)
    View Code
    shoppingcar.py
    """这是一个关于redis购物车的模块"""
    import json
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models
    from mysite import settings
    from django_redis import get_redis_connection
    from utils.response import BaseResponse
    
    USER_ID = 1    # 模拟用户
    
    
    class ShoppingCarViewSet(APIView):
        # 类下的全局变量
        conn = get_redis_connection("default")
    
        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:
                    # 价格策略不合法
                    ret.code = 1001
                    ret.error = "价格异常"
                    return Response(ret.dict)
                # 5.将购物信息添加到redis中
                car_key = settings.SHOPPING_CAR_KEY % (USER_ID, course_id)
                car_dict = {
                    "title": course.name,
                    "img": course.course_img,
                    "default_policy": policy_id,
                    "policy": json.dumps(price_policy_dict)
                }
                self.conn.hmset(car_key, car_dict)
                ret.data = "添加成功"
            except Exception as e:
                ret.code = 1002
                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 % (USER_ID, course_id) for course_id in course_id_list]
                self.conn.delete(*key_list)
            except Exception as e:
                ret.code = 1001
                ret.error = "删除失败"
            return Response(ret.dict)
    
        def patch(self, request, *args, **kwargs):
            """
            修改课程的价格策略
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            ret = BaseResponse()
            try:
                # 1.获取价格策略和课程id
                course_id = request.data.get("courseid")
                policy_id = request.data.get("policyid")
                # 2.拼接课程的key
                key = settings.SHOPPING_CAR_KEY % (USER_ID, course_id)
                if not self.conn.exists(key):
                    ret.code = 1001
                    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 = 1002
                    ret.data = "价格策略不合法"
                    return Response(ret.dict)
                # 4.在购物车中修改该课程默认价格策略
                self.conn.hset(key, "default_policy", policy_id)
                ret.data = "修改成功"
            except Exception as e:
                ret.code = 1003
                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 % (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)
    View Code
    payment.py
    """这是一个结算中心模块"""
    import json
    import datetime
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from django_redis import get_redis_connection
    from utils.response import BaseResponse
    from mysite import settings
    from api import models
    
    USER_ID = 1
    
    
    class PayMentViewSet(APIView):
        conn = get_redis_connection("default")
    
        def post(self, request, *args, **kwargs):
            """
            购物车数据提交到结算中心
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            ret = BaseResponse()
            try:
                # 清空当前用户结算中心的数据
                key_list = self.conn.keys(settings.PAYMENT_KEY % (USER_ID, "*"))
                key_list.append(settings.PAYMENT_COUPON_KEY % (USER_ID))
                self.conn.delete(*key_list)
    
                payment_dict = {}
                # 通用优惠券
                global_coupon_dict = {
                    "coupon": {},
                    "default_coupon": 0
                }
                # 1.获取用户要结算课程id
                course_id_list = request.data.get("courseids")
                for course_id in course_id_list:
                    car_key = settings.SHOPPING_CAR_KEY % (USER_ID, course_id)
                    # 1.1结算时检测用户的课程是否已经加入购物车
                    if not self.conn.exists(car_key):
                        ret.code = 1001
                        ret.error = "课程需要先加入购物车才能结算"
                        return Response(ret.dict)
                    # 1.2从购物车中获取价格策略和默认价格,放入到结算中心
                    policy = json.loads(self.conn.hget(car_key, "policy").decode("utf-8"))
                    default_policy = self.conn.hget(car_key, "default_policy").decode("utf-8")
                    policy_info = policy[default_policy]
    
                    payment_course_dict = {
                        "course_id": str(course_id),
                        "title": self.conn.hget(car_key, "title").decode("utf-8"),
                        "img": self.conn.hget(car_key, "img").decode("utf-8"),
                        "policy_id": default_policy,
                        "coupon": {},            # 优惠券
                        "default_policy": 0        # 默认没有选择优惠券
                    }
                    payment_course_dict.update(policy_info)
                    payment_dict[str(course_id)] = payment_course_dict
    
                # 1.3获取优惠券
                ctime = datetime.date.today()
                coupon_list = models.CouponRecord.objects.filter(
                    account=USER_ID,
                    status=0,
                    coupon__valid_begin_date__lte=ctime,    # 优惠券开始时间小于等于今天
                    coupon__valid_end_date__gte=ctime,
                )
                for item in coupon_list:
                    # 通用优惠券
                    if not item.coupon.object_id:
                        coupon_id = item.id
                        # 优惠券的类型: 满减、折扣、立减
                        coupon_type = item.coupon.coupon_type
                        # 获取编号和中文解释
                        info = {}
                        info["coupon_type"] = coupon_type
                        info["coupon_display"] = item.coupon.get_coupon_type_display()
                        if coupon_type == 0:     # 立减
                            info["money_equivalent_value"] = item.coupon.money_equivalent_value
                        elif coupon_type == 1:    # 满减券
                            info["money_equivalent_value"] = item.coupon.money_equivalent_value
                            info["minimum_consume"] = item.coupon.minimum_consume
                        else:   # 折扣
                            info["off_percent"] = item.coupon.off_percent
                        # 通用优惠券
                        global_coupon_dict["coupon"][coupon_id] = info
                        continue
                    # 绑定课程优惠券id
                    coupon_course_id = str(item.coupon.object_id)
                    # 优惠券id
                    coupon_id = item.id
                    # (优惠券规则表)优惠券类型: 满减、折扣、立减
                    coupon_type = item.coupon.coupon_type
                    info = {}
                    info["coupon_type"] = coupon_type
                    info["coupon_display"] = item.coupon.get_coupon_type_display()
                    if coupon_type == 0:    # 立减
                        info["money_equivalent_value"] = item.coupon.money_equivalent_value
                    elif coupon_type == 1:   # 满减券
                        info["money_equivalent_value"] = item.coupon.money_equivalent_value
                        info["minimum_consume"] = item.coupon.minimum_consume
                    else:   # 折扣
                        info["off_percent"] = item.coupon.off_percent
    
                    if coupon_course_id not in payment_dict:
                        # 获取到优惠券,但是没有购买此课程
                        continue
                    # 将优惠券设置到指定的课程字典中
                    payment_dict[coupon_course_id]["coupon"][coupon_id] = info
                # 1.4将绑定优惠券课程写入到redis中(结算中心)
                for cid, cinfo in payment_dict.items():
                    pay_key = settings.PAYMENT_KEY % (USER_ID, cid)
                    cinfo["coupon"] = json.dumps(cinfo["coupon"])
                    self.conn.hmset(pay_key, cinfo)
                # 1.5将通用优惠券写入到redis中
                gcoupon_key = settings.PAYMENT_COUPON_KEY % (USER_ID,)
                global_coupon_dict["coupon"] = json.dumps(global_coupon_dict["coupon"])
                self.conn.hmset(gcoupon_key, global_coupon_dict)
                ret.data = "提交成功"
            except Exception as e:
                ret.code = 1003
                ret.error = "提交失败"
            return Response(ret.dict)
    
        def patch(self, request, *args, **kwargs):
            """
            选择优惠券
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            ret = BaseResponse()
            try:
                # 1.用户提交要选择的优惠券
                course = request.data.get("courseid")
                course_id = str(course) if course else course
                coupon_id = str(request.data.get("courseid"))
                redis_global_coupon_key = settings.PAYMENT_COUPON_KEY % (USER_ID,)
                # 1.1修改通用优惠券
                if not course_id:
                    if coupon_id == "0":
                        # 不使用优惠券请求数据
                        self.conn.hset(redis_global_coupon_key, "default_coupon", coupon_id)
                        ret.data = "修改成功"
                        return Response(ret.dict)
                    # 使用优惠券请求数据
                    coupon_dict = json.loads(self.conn.hget(redis_global_coupon_key, "coupon").decode("utf-8"))
                    # 判断用户选择的优惠券是否合法
                    if coupon_id not in coupon_dict:
                        ret.code = 1003
                        ret.error = "通用优惠券不存在"
                        return Response(ret.dict)
                    # 选择的优惠券合法
                    self.conn.hset(redis_global_coupon_key, "default_coupon", coupon_id)
                    ret.data = "修改成功"
                    return Response(ret.dict)
                # 修改课程优惠券
                redis_payment_key = settings.PAYMENT_KEY % (USER_ID, course_id)
                # 不使用优惠券
                if coupon_id == "0":
                    self.conn.hset(redis_payment_key, "default_coupon", coupon_id)
                    ret.data = "修改成功"
                    return Response(ret.dict)
                # 使用优惠券
                coupon_dict = json.loads(self.conn.hget(redis_payment_key, "coupon").decode("utf-8"))
                if coupon_id not in coupon_dict:
                    ret.code = 1003
                    ret.error = "课程优惠券不存在"
                    return Response(ret.dict)
                self.conn.hset(redis_payment_key, "default_coupon", coupon_id)
                ret.data = "修改课程优惠券成功"
            except Exception as e:
                ret.code = 1002
                ret.error = "修改失败"
            return Response(ret.dict)
    
        def get(self, request, *args, **kwargs):
            """
            查看优惠券信息
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            ret = BaseResponse()
            try:
                # payment_1_*
                redis_payment_key = settings.PAYMENT_KEY % (USER_ID, "*")
                # payment_coupon_1
                redis_global_coupon_key = settings.PAYMENT_COUPON_KEY % (USER_ID,)
                # 1.获取绑定课程信息
                course_list = []
                for key in self.conn.scan_iter(redis_payment_key):
                    info = {}
                    data = self.conn.hgetall(key)
                    for k, v in data.items():
                        kk = k.decode("utf-8")
                        if kk == "coupon":
                            info[kk] = json.loads(v.decode("utf-8"))
                        else:
                            info[kk] = v.decode("utf-8")
                    course_list.append(info)
                # 通用优惠券
                global_coupon_didct = {
                    "coupon": json.loads(self.conn.hget(redis_global_coupon_key, "coupon").decode("utf-8")),
                    "default_coupon": self.conn.hget(redis_global_coupon_key, "default_coupon").decode("utf-8")
                }
                ret.data = {
                    "course_list": course_list,
                    "global_coupon_dict": global_coupon_didct
                }
            except Exception as e:
                ret.code = 1003
                ret.error = "获取失败"
            return Response(ret.dict)
    View Code
    app/urls.py
    from django.conf.urls import url
    from api.views import shoppingcar, payment, order
    
    urlpatterns = [
        url(r'^shoppingcar/$', shoppingcar.ShoppingCarViewSet.as_view()),
        url(r'^payment/$', payment.PayMentViewSet.as_view()),
        url(r'^order/$', order.OrderViewset.as_view()),
    ]
    View Code

    mysite/urls.py

    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/(?P<version>w+)/', include("api.urls")),
    ]
    View Code

    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
    
    }
    
    # redis设置
    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": 100},
                 "PASSWORD": "123456",
            }
        }
    }
    
    # 购物车相关设置
    SHOPPING_CAR_KEY = "shopping_car_%s_%s"
    PAYMENT_KEY = "payment_%s_%s"
    PAYMENT_COUPON_KEY = "payment_coupon_%s"
    View Code

    utils/response.py

    class BaseResponse(object):
    
        def __init__(self):
            self.code = 1000
            self.data = None
            self.error = None
    
        @property
        def dict(self):
            return self.__dict__
    View Code
  • 相关阅读:
    Cannot run program "/home/mohemi/Program/adt-bundle-linux-x86_64-20130729/sdk//tools/emulator": error=2, 没有那个文件或目录
    在Ubuntu里部署Javaweb环境脑残版
    ios 内存管理 心得
    关于Servlet的PrintWriter 中文乱码问题
    流的对拷
    什么是javaBean
    ios 页面传值4种方式(四) 之通过delegate(代理)
    ios 页面传值4种方式(一) 之全局变量
    Block
    UIView动画学习笔记
  • 原文地址:https://www.cnblogs.com/Guishuzhe/p/9756143.html
Copyright © 2011-2022 走看看