python 计算订单_python 全栈开发,Day105(路飞其他数据库表结构,立即结算需求)

考试第三部分:Django

16. 列列举你熟悉的Http协议头以及作用。(1分)

ContractedBlock.gif

ExpandedBlockStart.gif

Accept-Charset: 用于告诉浏览器,客户机采用的编码

Host: 客户机通过这个头告诉服务器,想访问的主机名

User-Agent: 客户机通过这个头告诉服务器,客户机的软件环境

Cookie: 客户机通过这个头可以向服务器带数据

View Code

17. 状态码含义:200、301、302、304、404、500。(2分)

ContractedBlock.gif

ExpandedBlockStart.gif

200请求已成功301永久重定向302临时重定向304未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源404资源找不到500 服务器内部错误,无法完成请求

View Code

18. 简述cookie和session?(2分)

ContractedBlock.gif

ExpandedBlockStart.gif

cookie是保存在客户端浏览器的,每次请求网页,会携带cookie

session是保存在服务器上面的,用来判断请求客户端的cookie是否合法

View Code

19. django中get和filter的区别?(1分)

ContractedBlock.gif

ExpandedBlockStart.gif

get 返回一个object。当返回结果,有且只有一条时,才会返回。否则报错

filter 返回一个queryset对象。即使没有匹配到条件,不会报错,返回一个空的queryset对象

View Code

20. django的中间件在1.7和1.11版本间有什什么区别?(1分)

ContractedBlock.gif

ExpandedBlockStart.gif

1. 路由编写2. ORM中,外键一定要有on_delete属性3. 中间件4. 模板配置

View Code

21. django中contenttypes组件的作⽤用?(1分)

ContractedBlock.gif

ExpandedBlockStart.gif

用来解决一个对和多个表做外键关联,并且关联的字段,不会在表中产生新的字段

View Code

22. django中Q的作⽤用?(2分)

ContractedBlock.gif

ExpandedBlockStart.gif

用来做一些复杂查询,比如or

View Code

23. 将如下SQL语句句使⽤用Django的ORM实现:(3分)

select * from order where id >= 12

ContractedBlock.gif

ExpandedBlockStart.gif

order.object.filter(id__gte=12)

View Code

select * from order where id != 12

ContractedBlock.gif

ExpandedBlockStart.gif

order.object.filter(id__exclude=12)

View Code

select * from order where id in [1,3,4]

ContractedBlock.gif

ExpandedBlockStart.gif

order.object.filter(id__in=[1,3,4])

View Code

select * from order where id between 20 and 100

ContractedBlock.gif

ExpandedBlockStart.gif

order.object.filter(id__range([20,100])

View Code

select * from order where id > 20 and (num < 60 or num > 70 )

ContractedBlock.gif

ExpandedBlockStart.gif

#注意:Q(id__gt=20)是一组查询,&表示and,| 表示or#Q(Q(num__lt=60)|Q(num__gt=70)) 是另外一组查询

order.object.filter(Q(id__gt=20) & Q(Q(num__lt=60)|Q(num__gt=70)))

View Code

select * from order order by id desc,age asc

ContractedBlock.gif

ExpandedBlockStart.gif

#默认使用asc(升序),-id表示以id字段,进行desc(降序)来排序

order.object.all().order_by('-id','age')

View Code

24. 编写查询语句句:(5分,前2个每个1分,最后⼀一题3分)

• 查看所有学⽣生,并打印 姓名、班级名称

ContractedBlock.gif

ExpandedBlockStart.gif

#注意:一定要以Student为基准表#当filter字段有其他表时,使用inner join。当使用values时,它是left join#一个班级在创建的时候,是没有学生的。所以以classes为基础表时,会造成数据不准确

Student.objects.all().values('name','classes__name')

View Code

• 查看班级名称为"全栈12期"的所有学⽣生

ContractedBlock.gif

ExpandedBlockStart.gif

Classes.object.filter(name="全栈12期").value("student__name")

View Code

• 查看没有学⽣生的所有班级ID、班级名称

ContractedBlock.gif

ExpandedBlockStart.gif

#当班级表的学生记录为空时,使用student__isnull=True

Classes.objects.filter(student__isnull=True).values('id','name')

View Code

25. django中遇到复杂的SQL时ORM⽆无法完成,如何使⽤用原⽣生SQL执⾏行行?(2分)

ContractedBlock.gif

ExpandedBlockStart.gif

1. 根据connections['default'].cursor(),最接近于pymysql操作2. 使用extra

View Code

cursor = connection.cursor() 表示连接默认的数据库,看settings.py中的数据库配置

ContractedBlock.gif

ExpandedBlockStart.gif

DATABASES ={'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

}

}

View Code

defalut表示默认的数据库。django可以同时连接多个数据库,可以这样

ContractedBlock.gif

ExpandedBlockStart.gif

DATABASES ={'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

},'default2': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

}

}

View Code

extra是django自带的,默认就可以使用。而connection使用时,需要导入模块!

详情请参考链接:

搜索 "其他操作",展开里面的代码,就可以看到了!

一、路飞其他数据库表结构

深科技

先来看深科技的相关表

ContractedBlock.gif

ExpandedBlockStart.gif

#############深科技相关 ###################

classArticleSource(models.Model):"""文章来源"""name= models.CharField(max_length=64, unique=True)classMeta:

verbose_name_plural= "16. 文章来源"

def __str__(self):returnself.nameclassArticle(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)

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="位置")

comment= GenericRelation("Comment") #用于GenericForeignKey反向查询, 不会生成表字段,切勿删除,如有疑问请联系老村长

classMeta:

verbose_name_plural= "17. 文章"

def __str__(self):return "%s-%s" %(self.source, self.title)classArticleDetail(models.Model):"""文章详细"""article= models.OneToOneField(to='Article')

content= models.TextField(verbose_name="文章正文")classCollection(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)classMeta:

unique_together= ('content_type', 'object_id', 'account')

verbose_name_plural= "18. 通用收藏表"

classComment(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):returnself.contentclassMeta:

verbose_name_plural= "19. 通用评论表"

View Code

打开网页: https://www.luffycity.com/news

1341090-20180815160406683-1411354871.png

Article

中间的 斯嘉丽约翰逊 就是banner大图,对应Article表中position_choices类型

banner大图右边的罗胖子,是banner小图

banner大图下面的文章列表,表示信息流

ArticleDetail

文章详情表,存放了文章详情。里面包含了大量的html标签!占用空间比较大。它需要单独拆分。

它和文章表,做了一对一关联。也就是外键+唯一索引

Collection

通用评论表,看下面这几行代码

content_type =models.ForeignKey(ContentType)

object_id=models.PositiveIntegerField()

content_object= GenericForeignKey('content_type', 'object_id')

如果要使用django ContentType组件,上面这3行,是必须要有的!不要问我为什么,这是约定俗成的!

例如:文章,课程,视频...,这些都需要评论。通常的做法是给这些表做外键,关联到评论表。那么这些表在数据库中会产生一个关联字段!

使用 ContentType组件后,只需要在这些表加一个属性等于GenericRelation("Collection"),那么就可以建立关联了。而且数据库不会产生新的字段!所以说,它是一个通用的评论表

订单相关

再来看订单相关的表

ContractedBlock.gif

ExpandedBlockStart.gif

################## 订单相关 #################

classEnrolledCourse(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)classMeta:

verbose_name_plural= "34. 报名专题课"

classScoreRule(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)classMeta:

unique_together= ('rule', 'score_type')

verbose_name_plural= "29. 奖惩规则"

classScoreRecord(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" %(self.id, self.score_rule, self.account, self.score,)classMeta:

verbose_name_plural= "30. 奖惩记录"

classCourseSchedule(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)classMeta:

unique_together= ('study_record', 'homework')

verbose_name_plural= "33. 课程模块计划表(学位课)"

classStudyRecord(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)classMeta:

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)classDegreeRegistrationForm(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)classMeta:

verbose_name_plural= "35. 报名表(学位课)"

def __str__(self):return "%s" %self.enrolled_degreeclassEnrolledDegreeCourse(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)classMeta:

unique_together= ('account', 'degree_course')

verbose_name_plural= "36. 报名学位课"

classOrder(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="订单取消时间")classMeta:

verbose_name_plural= "37. 订单表"

def __str__(self):return "%s" %self.order_numberclassOrderDetail(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)classMeta:

verbose_name_plural= "38. 订单详细"unique_together= ("order", 'content_type', 'object_id')classTransactionRecord(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)classMeta:

verbose_name_plural= "40. 贝里交易记录"

def __str__(self):return "%s" %self.transaction_numberclassHomeworkRecord(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="提交日期")#homework_path = models.CharField(verbose_name='作业路径', max_length=256,blank=True,null=True) 作业路径可以动态拿到,没必要存

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)classMeta:

verbose_name_plural= "41. 作业"unique_together= ("homework", "student")classStuFollowUpRecord(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)classMeta:

verbose_name_plural= "42. 学员跟进记录"

def __str__(self):return "%s --%s --%s" % (self.enrolled_degree_course, self.record, self.date)

View Code

假设一个订单号20242359346940369,里面包含了10个课程。要如何体现一个订单号有10个课程呢?

需要这样设计

订单表

+----+-----------+----------+

| id | 订单号 | 用户id |

+----+-----------+----------+

| 1 | 335446557 | 234 |

+----+-----------+----------+

订单详细表

+----+-----------+----------+--------+--------+--------+

| id | 订单id | 课程id | 原价 | 价格 | 周期 |

+----+-----------+----------+--------+--------+--------+

| 1 | 335446557 | 12 | 20 | 15 | 7 |...+----+-----------+----------+--------+--------+--------+

Order

订单表,payment_number表示支付第3方订单号。比如:用户使用支付宝付款后,支付宝会发送一条POST请求,访问你的服务器,它会携带一个支付宝产生的订单号。这个就是payment_number的作用,用来进行后续的查询是否到账了!

actual_amount 表示抛开使用优惠券,贝里之后,实际付款的金额!

OrderDetail

订单详细表,content表示备注,用来给运营人员来加一些备注信息!

TransactionRecord

贝里交易纪录,当付款使用贝里时,这里会产生一条记录!

DegreeRegistrationForm

学位课程报名表,当用户购买学位课程后,是不能直接观看视频的。需要添加报名表才行,需要填写一些相关信息。有了这些信息后,才能给用户分配导师,促进学习!

ScoreRule

积分规则,主要约束导师的。初始分配:学员分配到某位导师后,这位导师的账户就会多一些积分,比如1500贝里。

如果学员未交作业,导师没有批改作业,受到学员投诉.... 都是要扣贝里的。这些贝里,到一定时间是可以提现的!

成熟周期这里注释掉了,意思就是学员毕业,就可以提现了!

在linux上面做了一个任务计划,每天凌晨2点跑一个脚本,用来更新成熟周期。

EnrolledCourse

已报名课程,不包括学位课程。也就是说,它只负责专题课。

当用户购买一个专题课后,需要在EnrolledCourse,Order,OrderDetail。这3个表产生记录即可

如果使用贝里支付,还需要操作TransactionRecord表。

设计到优惠券,还需要操作优惠券相关的表

如果是购买了学位课,除了EnrolledCourse表之外,其他表都要操作!

二、立即结算需求

看结算页面

1341090-20180815170517768-1266909309.png

当点击立即支付时,会向后端发送一些数据。发送哪些数据呢?

将页面的课程相关信息都发送过去?没有必要!为什么呢?

因为结算中心的数据,是存放在redis中的。所以发送时,只需要发送2个数据。

使用的贝里数,以及经过计算后的金额。后端接收到这2个数据时,再根据结算中心的数据,做计算。

当前端发送的金额和后端计算的金额一致时,跳转到支付宝页面,否则提示计算错误!

为什么呢?因为用户页面看到的是498,结果跳转到支付宝页面时,要付款510块,用户肯定不干了!

计算规则是这样的,先计算使用绑定课程的优惠券,然后将所有计算后的所有课程,做一个总价。

最后使用未绑定课程的优惠券,对总价进行计算。再使用贝里抵扣,最终得到实际付款金额!

注意:如果优惠券的金额大于实际课程的金额,则按照实际扣除。那么这个优惠券就不能使用了!没有返现的功能!

多个表操作时,要基于事务来做

总结:

ContractedBlock.gif

ExpandedBlockStart.gif

后端接收:

贝里的数量和付款金额

a. 去结算中心获取要支付课程

b. 生成订单

c. 生成 订单详细,专题课购买表(如果优惠券>实际金额,则按照实际扣款)

d. 如果使用了贝里,在贝里交易表中,记录一下;

e. 优惠券表更新

f. 计算规则:

前端发送的金额和后端计算的金额-->相同,跳转到支付宝支付;

后端计算规则:

先计算绑定课程的优惠券

总价再使用未绑定课程优惠券

贝里抵扣

最终得到,实际付款金额

注意:多个表操作,使用事务

View Code

作业:

1.继续完成结算中心逻辑

2.熟悉今天的表结构

结算中心逻辑

修改views目录下的payment.py

create和list代码如下:

ContractedBlock.gif

ExpandedBlockStart.gif

importjsonimportredisfrom django.conf importsettingsfrom rest_framework.views importAPIViewfrom rest_framework.viewsets importViewSetMixinfrom rest_framework.response importResponsefrom api.utils.auth importLuffyAuthenticationfrom api importmodelsfrom api.utils.response importBaseResponsefrom django_redis importget_redis_connection

CONN= get_redis_connection("default") #使用redis连接池

classPaymentView(ViewSetMixin, APIView):

authentication_classes=[LuffyAuthentication, ]def create(self, request, *args, **kwargs):"""在结算中添加课程

:param request:

:param args:

:param kwargs:

:return:"""

#1.接收用户选择的要结算的课程ID列表

choice_list = request.data.get('course_id')#print(choice_list)

#2.清空当前用户request.user.id结算中心的数据

#key = payment_1*

CONN.delete('payment_1*')#3.循环要加入结算中的所有课程ID列表

"""for course_id in 用户提交课程ID列表:

3.1 根据course_id,request.user.id去购物车中获取商品信息:商品名称、图片、价格(id,周期,显示周期,价格)

3.2 根据course_id,request.user.id获取

- 当前用户

- 当前课程

- 可用的优惠券

加入结算中心

提示:可以使用contenttypes"""

'''# 2.1 课程是否存在?

temp = {

'id': CONN.hget(key, 'id').decode('utf-8'),

'name': CONN.hget(key, 'name').decode('utf-8'),

'img':CONN.hget(key, 'img').decode('utf-8'),

'default_price_id':CONN.hget(key, 'default_price_id').decode('utf-8'),

'price_policy_dict': json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))

}'''user_id=request.user.idprint('用户id', user_id)#从购物车中获取数据

pattern = "shopping_car_%s_%s" % (request.user.id, '*',)#print(pattern)

user_key_list =CONN.keys(pattern)for course_id in choice_list: #用户选择的要结算的课程ID列表

for key in user_key_list: #当前用户购物车列表

id = CONN.hget(key, 'id').decode('utf-8') #获取购物车课程id

if id == course_id: #判断用户选择课程id和购物车课程id相等

name = CONN.hget(key, 'name').decode('utf-8') #课程名

default_price_id = CONN.hget(key, 'default_price_id').decode('utf-8') #默认价格策略id

#所有价格策略

price_policy_dict = json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))print('课程id',id)print('课程名',name)print('默认价格策略',default_price_id)

valid_period= price_policy_dict[default_price_id].get('valid_period_display')print('有效期', valid_period)print('原价',price_policy_dict[default_price_id].get('price'))print('折后价', price_policy_dict[default_price_id].get('price'))print('所有价格策略',price_policy_dict)#加入结算中心redis

j_key = "payment_%s_%s" %(user_id, id,)

CONN.hset(j_key,'id', course_id)

CONN.hset(j_key,'name', name)

CONN.hset(j_key,'price_id', default_price_id)

CONN.hset(j_key,'price', price_policy_dict[default_price_id].get('price'))

CONN.hset(j_key,'valid_period', valid_period)

CONN.hset(j_key,'discount_price', price_policy_dict[default_price_id].get('price'))#查询当前课程的 绑定课程优惠券

obj1 = models.Course.objects.filter(id=id).first()if obj1.coupon.all(): #反向查询该课程的所有优惠券

print("绑定课程优惠券#########################")for i in obj1.coupon.all(): #循环每一个优惠券

print('绑定课程优惠券个数',len(obj1.coupon.all()))

coupon_dict= {} #空字典

for j in range(len(obj1.coupon.all())): #for循环长度

if i.coupon_type == 0: #类型为立减

coupon_dict[j] = '{}{}'.format(i.get_coupon_type_display(), i.money_equivalent_value)#增加到redis中

CONN.hset(j_key, 'coupon_dict', coupon_dict)#print(111)

print('{}{}'.format(i.get_coupon_type_display(), i.money_equivalent_value))elif i.coupon_type == 1:

coupon_dict[j]= '满{}减{}'.format(i.minimum_consume, i.money_equivalent_value)

CONN.hset(j_key,'coupon_dict', coupon_dict)print('满{}减{}'.format(i.minimum_consume, i.money_equivalent_value))else:#print(i.id)

coupon_dict[j] = '{}折'.format(i.off_percent)

CONN.hset(j_key,'coupon_dict', coupon_dict)print('{}折'.format(i.off_percent))#绑定课程的优惠券

#obj = models.CouponRecord.objects.filter(account=user_id, coupon__object_id__isnull=False)

#print('绑定课程优惠券#################')

#if obj:

#for i in obj:

#if i.coupon.coupon_type == 0:

#print('{}{}'.format(i.coupon.get_coupon_type_display(), i.coupon.money_equivalent_value))

#elif i.coupon.coupon_type == 1:

#print('满{}减{}'.format(i.coupon.minimum_consume, i.coupon.money_equivalent_value))

#else:

## print(i.coupon.id)

#print('{}折'.format(i.coupon.off_percent))

#4.获取当前用户所有未绑定课程优惠券

#- 未使用

#- 有效期内

#- 加入结算中心:glocal_coupon_用户ID

#当前用户未绑定课程的优惠券

obj2 = models.CouponRecord.objects.filter(account=user_id, coupon__object_id__isnull=True)print('未绑定课程优惠券#################')ifobj2:#通用优惠券redis key

coupon_key = "general_coupon_%s" %(user_id)for i inobj2:

general_coupon_dict= {} #空字典

print('未绑定课程优惠券个数 %s' %(len(obj2)))for j inrange(len(obj2)):if i.coupon.coupon_type == 0: #类型为立减

general_coupon_dict[j] = '{}{}'.format(i.coupon.get_coupon_type_display(), i.coupon.money_equivalent_value)

CONN.hset(coupon_key,'coupon_dict', general_coupon_dict)print('{}{}'.format(i.coupon.get_coupon_type_display(), i.coupon.money_equivalent_value))elif i.coupon.coupon_type == 1:

general_coupon_dict[j]= '满{}减{}'.format(i.coupon.minimum_consume, i.coupon.money_equivalent_value)

CONN.hset(coupon_key,'coupon_dict', general_coupon_dict)print('满{}减{}'.format(i.coupon.minimum_consume, i.coupon.money_equivalent_value))else:

general_coupon_dict[j]= '{}折'.format(i.coupon.off_percent)

CONN.hset(coupon_key,'coupon_dict', general_coupon_dict)print('{}折'.format(i.coupon.off_percent))return Response('ok')def list(self, request, *args, **kwargs):"""查看结算中心

:param request:

:param args:

:param kwargs:

:return:"""

#1. 根据用户ID去结算中心获取该用户所有要结算课程

course_id = request.query_params.get('course_id')print('课程id',course_id)

obj= models.Course.objects.filter(id=course_id).first()print('结算课程',obj.name)#2. 根据用户ID去结算中心获取该用户所有可用未绑定课程的优惠券

user_id =request.user.idprint('用户id', user_id)

obj2= models.CouponRecord.objects.filter(account=user_id, coupon__object_id__isnull=True)ifobj2:for i inobj2:if i.coupon.coupon_type ==0:print('{}{}'.format(i.coupon.get_coupon_type_display(), i.coupon.money_equivalent_value))elif i.coupon.coupon_type == 1:print('满{}减{}'.format(i.coupon.minimum_consume, i.coupon.money_equivalent_value))else:print(i.coupon.id)print('{}折'.format(i.coupon.off_percent))#3. 用户表中获取贝里余额

beili = models.Account.objects.filter(id=user_id).first()print('用户贝里',beili.balance)#4. 以上数据构造成一个字典

return Response('...')def update(self, request, *args, **kwargs):"""更新优惠券

:param request:

:param args:

:param kwargs:

:return:"""

#1. 获取用户提交:

#course_id=1,coupon_id=3

#course_id=0,coupon_id=6

#2. course_id=1 --> 去结算中心获取当前用户所拥有的绑定当前课程优惠,并进行校验

#- 成功:defaul_coupon_id=3

#- 否则:非法请求

#3. course_id=0 --> 去结算中心获取当前用户所拥有的未绑定课程优惠,并进行校验

#- 成功:defaul_coupon_id=3

#- 否则:非法请求

View Code

使用postman测试 create

1341090-20180815220811673-1503260737.png

查看Pycharm控制台输出:

ContractedBlock.gif

ExpandedBlockStart.gif

用户id 1课程id1课程名 Python开发入门7天特训营

默认价格策略1有效期 1周

原价10.0折后价10.0所有价格策略 {'2': {'valid_period': 30, 'id': 2, 'price': 50.0, 'valid_period_display': '1个月'}, '1': {'valid_period': 7, 'id': 1, 'price': 10.0, 'valid_period_display': '1周'}}

绑定课程优惠券#########################

绑定课程优惠券个数 28折

8折

绑定课程优惠券个数2满50减10

满50减10

未绑定课程优惠券#################

未绑定课程优惠券个数 1立减10

View Code

使用postman测试 list

1341090-20180815221124885-1536648442.png

查看Pycharm控制台输出:

ContractedBlock.gif

ExpandedBlockStart.gif

课程id 1结算课程 Python开发入门7天特训营

用户id1立减10

用户贝里100.0

View Code

说明:

结算中心有2个key

一个是结算中心key

结算中心 ={'payment_用户id_课程id':{

id:课程id,

mame:课程名,

price_id:价格策略id,

price:原价,

valid_period:有效期,

discount_price:折后价,

coupon_dict: {#绑定课程优惠券

1:'优惠券1',2:'优惠券2',3:'优惠券3',

}

},

}

一个是用户通用优惠券,也就是未绑定课程优惠券

用户通用优惠券 ={'general_coupon_用户id':{

coupon_dict: {#未绑定课程优惠券

1:'优惠券1',2:'优惠券2',3:'优惠券3',

}

},

}

我没有把通用优惠放在结算中心key里面,为什么呢?

因为结算中心的key,都是用户id_课程id。如果用户购买了10个课程,那么就会产生10个key。

而每个key都用存储通用优惠券,那么这个通用优惠券重复了10次,完全没有必要!

所以我单独分离出来了!

完整代码请参考github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值