K12(在线学习的平台)
項目:K12(在線學習的平臺)
一、背景
目的是做一個在線的學習平臺,提高學生的課程完成度
K12:大目標是要取代線下班
- - 錄制專門的視頻
- - 導師的監管:如果沒有主動和那個學生聊天,就扣錢
- - 學生的激勵:如果提前學完了,學習能力很強,可以免學費
二、系統架構
- 主站- rest api - vue - 導師后臺 (stark)- django - stark - 管理后臺 (stark)- django - stark
三、人員和部門
- 后端開發(5人)- 主站(3)- 導師后臺(1)- 管理后臺(1) - 前端開發(1) - UI (1) - 測試(1) - 運維(部署:上線)(1) - 運營(推廣出去)(2) - 銷售 (2) - 導師 (2) - 產品經理 (1)- 人事 - 財務
四、需求分析
主站- 課程- 普通課程、學位課- 普通課程:比較小的課程- 學位課:從開始+項目+就業 - 分配一對一的導師- 導師對你進行監管,督促你學習- 保就業- 如果你%50的時間學完了,退一般的學費,等。- 課程列表、課程詳細- 課程周期的不同定價格- 個人的課程中心- 支付- 銀聯- 支付寶- 微信- 優惠券策略(滿減(滿多少減多少),立減,打折)- 貝里:可直接抵現金- 個人購物車- 深科技- 文章或者爬取的別人的文章(運營需要審核)
- 深刻有哪些功能?
- 點贊、評論、查看、收藏 - 登錄 、注冊 導師后臺 管理后臺
具體進一步談業務需求
a、課程:業務相關:1、學位課,如果你學的快;最多返指定金額的65%2、作業做的好,會把額外的35%返給你3、普通課程購買課程后,在我的訂單中去評價4、購物車的數據沒有數據表。保存到redis里面去了兩大部分操作#redis操作在課程詳細頁面,選擇價格策略,點擊加入購物車,吧視頻和價格策略放到了redis中在購物車頁面,可以對redis中保存的購買的視頻數據和價格數據可以刪除,修改,添加,查看(刷新)選中,去結算中心#數據庫操作#pip freeze > requirement.txt #生成文件#pip install -r requirement.txt #下載所有的版本在結算頁面:優惠券- 選擇單一的優惠券(通用、滿減、折扣)- 課程優惠券:綁定課程的優惠券- 選擇全站的優惠券(通用、滿減、折扣)#單一的優惠券用完,再計算,看是否滿足全站的通用卷- 選擇貝里- 選擇支付寶,點擊立即支付- 在數據庫中生成一個訂單這個訂單如果用了優惠券,優惠券狀態改為已使用如果用了貝里,貝里的金額減少如果取消訂單,優惠券才不是使用狀態在支付頁面,掃碼狀態為已支付在我的訂單中應該去數據庫中讀數據在購物車或者結算中心的時候去redis里面讀數據課程列表和課程詳細等等等如果購買課程- 普通課程- 學位課程- 每個模塊生成記錄(人和課程模塊的記錄) - 買完之后自動生成- 開通模塊(后臺)- 導師跟進(導師)- 交作業(主站)b、深科技相關來源文章收藏通用評論表c、購買支付流程課程id和價格策略id傳值的時候可以傳兩個值- 通過策略id找到買的那個課程- 通過課程id 獲取所有的價格策略處理請求1、檢測課程是否上線,下線2、通過課程id 獲取所有的價格策略,和傳過來的進行對比3、檢測用戶提交的價格策略是否在所有的價格策略中4、將購物的視頻添加到購物車(redis) - 同一個課程只能買一個,不允許一下加入兩個吧數據放到redis中,那么怎么存?一個人就有一個購物車。可以通過用戶id來存所有的購物車= {1:{課程id1:{'prices':[],'price':9,'title':'python','img':'課程圖片'},課程id2:{'prices':[]}} }#如果看到課程已經在里面了,就不在里面添加了,這也就是用redis的原因class ShoppingCat(APIView):def post():#點擊加入購物車保存數據到redisdef get():#查看購物車列表def delete():#刪除def patch():#局部更新pass5、去結算(先簡單的說一下)買的所有的課程課程1 價格策略 課程2 價格策略 課程3 價格策略 點擊了去結算優惠券貝里 五、表結構
課程相關的13張表
課程大類表:e.g 前端,后端課程子類表:e.g python ,linux普通課程表學位課表##學位課可以有如下好處學位獎學金表
##當然學位課和普通課程共有的價格策略表優惠券表
課程詳細表課程章節表課程目錄表課程問答表課程評價(先不討論)
課程大綱
##老師表contenttype contentType 可以一下關聯兩張表,django自己提供了,不用自己創建
深科技相關的4張表
文章來源
文章資訊
收藏(既能收藏課程,也能收藏文章,可以用contenttype)
評論(可以用contenttype的形式也可以用ForeignKey的形式)
用戶相關的兩張表
用戶信息表account
用戶認證表userauthtoken
- 如果用戶初次登錄,給用戶創建一個token,如果已經有token了,下次用戶訪問的時候直接帶上token,如果沒有token就說明沒有登錄,就沒有訪問其他頁面的權限
購買支付相關的7張表
已報名課程表EnrolledCourse(誰購買了那個課程)
學位課報名表
已報名的學位課程表EnrolledDegreeCourse
優惠券發放、消費記錄
訂單表
訂單詳情
貝里交易記錄
其他相關的6張表
課程評價
學位課程評價
學位課程的模塊學習進度
為學生開通一個模塊
學生作業記錄及成績
學員跟進記錄
1、簡單表結構設計分析:
需要知道的知識點:
現在學位課和普通課程都有自己的價格策略和優惠券,現在是學位課已經有了自己的價格策略,那么如果普通課程也要加價格策略,怎么弄呢?
一下有三種方法:
方法一:再單獨創建一個表
方法二:不用單獨創建一個表,可以多添加一個字段,其中的一個為NULL。相比方法一省了一張表
方法三:可以通過ContentType ,這個表里面存的是應用的名字以及表名。但是在我們makemigrations和migrate的時候django已經幫我們創建好了,如下圖。就不用我們自己創建了
?這樣關聯的好處:可以ForeignKey任何一張表。里面的xid是關聯表的某一行數據,
這樣關聯以后,如果想在價格策略里面在添加一行數據,怎么添加呢?
有兩種方式:
方式一:手動插入
- 自己手動查出content_type_id 和關聯表里的某一行數據xid。查出來添加到價格策略表里面去
方式二:利用GenericForeignKey
- 可以通過導入?GenericForeignKey(GenericForeignKey有自動查找的功能,協助你快速做操作,沒有也可以,自己手動查詢)
from django.contrib.contenttypes.fields import GenericForeignKey
使用:
content_object = GenericForeignKey('content_type', 'object_id') #一下可以查到兩個表的數據,自動插入到價格策略表里了,
優惠券表也是如此。只是為了查詢方便 另外補充一個GenericRelation
from django.contrib.contenttypes.fields import GenericRelation
GenericRelation:也是幫助做快速查詢的,就像反向關聯的releated_name=‘xx’。以后查找的時候通可以通過點字段名的方式去查找
# 用于GenericForeignKey反向查詢, 不會生成表字段,切勿刪除coupon = GenericRelation("Coupon") #也是幫助做快速查詢的,可以直接查出所有的學位課的價格策略等 2、具體表結構設計如下:
1 from django.db import models2 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation3 #GenericForeignKey有自動查找的功能,協助你快速做操作,沒有也可以,自己手動查詢4 #GenericRelation:也是幫助做快速查詢的,可以直接查出所有的學位課的價格策略等5 6 from django.contrib.contenttypes.models import ContentType7 from django.db.models import Q8 from django.utils.safestring import mark_safe9 from django.db import models10 import hashlib11 12 class CourseCategory(models.Model):13 """課程大類, e.g 前端 后端..."""14 name = models.CharField(max_length=64, unique=True)15 16 def __str__(self):17 return "%s" % self.name18 19 class Meta:20 verbose_name = "課程大類" #單數21 verbose_name_plural = "課程大類" #復數22 23 class CourseSubCategory(models.Model):24 """課程子類, e.g python linux """25 category = models.ForeignKey("CourseCategory",verbose_name='所屬類')26 name = models.CharField(max_length=64, unique=True)27 28 def __str__(self):29 return "%s" % self.name30 31 class Meta:32 verbose_name = "課程子類"33 verbose_name_plural = "課程子類"34 35 class DegreeCourse(models.Model):36 """學位課程"""37 name = models.CharField(max_length=128, unique=True)38 course_img = models.CharField(max_length=255, verbose_name="縮略圖")39 brief = models.TextField(verbose_name="學位課程簡介", )40 total_scholarship = models.PositiveIntegerField(verbose_name="總獎學金(貝里)", default=40000)41 mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本課程的導師輔導費用(貝里)", default=15000)42 # 用于GenericForeignKey反向查詢, 不會生成表字段,切勿刪除43 coupon = GenericRelation("Coupon") #也是幫助做快速查詢的,可以直接查出所有的學位課的價格策略等44 # 為了計算學位獎學金45 period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=150)46 prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)47 teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")48 # 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除49 degreecourse_price_policy = GenericRelation("PricePolicy")50 51 def __str__(self):52 return self.name53 54 class Course(models.Model):55 """課程"""56 name = models.CharField(max_length=128, unique=True)57 course_img = models.CharField(max_length=255)58 sub_category = models.ForeignKey("CourseSubCategory")59 course_type_choices = ((0, '付費'), (1, 'VIP專享'), (2, '學位課程'))60 course_type = models.SmallIntegerField(choices=course_type_choices)61 degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是學位課程,此處關聯學位表")62 brief = models.TextField(verbose_name="課程概述", max_length=2048)63 level_choices = ((0, '初級'), (1, '中級'), (2, '高級'))64 level = models.SmallIntegerField(choices=level_choices, default=1)65 pub_date = models.DateField(verbose_name="發布日期", blank=True, null=True)66 period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=7)67 order = models.IntegerField("課程順序", help_text="從上一個課程數字往后排")68 attachment_path = models.CharField(max_length=128, verbose_name="課件路徑", blank=True, null=True)69 status_choices = ((0, '上線'), (1, '下線'), (2, '預上線'))70 status = models.SmallIntegerField(choices=status_choices, default=0)71 template_id = models.SmallIntegerField("前端模板id", default=1)72 coupon = GenericRelation("Coupon")73 # 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除74 price_policy = GenericRelation("PricePolicy")75 76 def __str__(self):77 return "%s(%s)" % (self.name, self.get_course_type_display())78 79 def save(self, *args, **kwargs):80 if self.course_type == 2:81 if not self.degree_course:82 raise ValueError("學位課程必須關聯對應的學位表")83 super(Course, self).save(*args, **kwargs)84 85 class CourseDetail(models.Model):86 """課程詳情頁內容"""87 course = models.OneToOneField("Course")88 hours = models.IntegerField("課時")89 course_slogan = models.CharField(max_length=125, blank=True, null=True)90 video_brief_link = models.CharField(verbose_name='課程介紹', max_length=255, blank=True, null=True)91 why_study = models.TextField(verbose_name="為什么學習這門課程")92 what_to_study_brief = models.TextField(verbose_name="我將學到哪些內容")93 career_improvement = models.TextField(verbose_name="此項目如何有助于我的職業生涯")94 prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)95 recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)96 teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")97 98 def __str__(self):99 return "%s" % self.course
100
101 class OftenAskedQuestion(models.Model):
102 """常見問題"""
103 content_type = models.ForeignKey(ContentType,
104 limit_choices_to={'model__contains': 'course'}) # 關聯course or degree_course
105 object_id = models.PositiveIntegerField()
106 content_object = GenericForeignKey('content_type', 'object_id')
107
108 question = models.CharField(max_length=255)
109 answer = models.TextField(max_length=1024)
110
111 def __str__(self):
112 return "%s-%s" % (self.content_object, self.question)
113
114 class Meta:
115 unique_together = ('content_type', 'object_id', 'question')
116
117 class CourseOutline(models.Model):
118 """課程大綱"""
119 course_detail = models.ForeignKey("CourseDetail")
120 title = models.CharField(max_length=128)
121 # 前端顯示順序
122 order = models.PositiveSmallIntegerField(default=1)
123
124 content = models.TextField("內容", max_length=2048)
125
126 def __str__(self):
127 return "%s" % self.title
128
129 class Meta:
130 unique_together = ('course_detail', 'title')
131
132 class CourseChapter(models.Model):
133 """課程章節"""
134 course = models.ForeignKey("Course", related_name='coursechapters')
135 chapter = models.SmallIntegerField(verbose_name="第幾章", default=1)
136 name = models.CharField(max_length=128)
137 summary = models.TextField(verbose_name="章節介紹", blank=True, null=True)
138 pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)
139
140 class Meta:
141 unique_together = ("course", 'chapter')
142
143 def __str__(self):
144 return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)
145
146 class Teacher(models.Model):
147 """講師、導師表"""
148 name = models.CharField(max_length=32)
149 role_choices = ((0, '講師'), (1, '導師'))
150 role = models.SmallIntegerField(choices=role_choices, default=0)
151 title = models.CharField(max_length=64, verbose_name="職位、職稱")
152 signature = models.CharField(max_length=255, help_text="導師簽名", blank=True, null=True)
153 image = models.CharField(max_length=128)
154 brief = models.TextField(max_length=1024)
155
156 def __str__(self):
157 return self.name
158
159 class PricePolicy(models.Model):
160 """價格與有課程效期表"""
161 content_type = models.ForeignKey(ContentType) # 關聯course or degree_course
162 object_id = models.PositiveIntegerField()
163 content_object = GenericForeignKey('content_type', 'object_id')
164
165 # course = models.ForeignKey("Course")
166 valid_period_choices = ((1, '1天'), (3, '3天'),
167 (7, '1周'), (14, '2周'),
168 (30, '1個月'),
169 (60, '2個月'),
170 (90, '3個月'),
171 (180, '6個月'), (210, '12個月'),
172 (540, '18個月'), (720, '24個月'),
173 )
174 valid_period = models.SmallIntegerField(choices=valid_period_choices)
175 price = models.FloatField()
176
177 class Meta:
178 unique_together = ("content_type", 'object_id', "valid_period")
179
180 def __str__(self):
181 return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
182
183 class CourseSection(models.Model):
184 """課時目錄"""
185 chapter = models.ForeignKey("CourseChapter", related_name='coursesections')
186 name = models.CharField(max_length=128)
187 order = models.PositiveSmallIntegerField(verbose_name="課時排序", help_text="建議每個課時之間空1至2個值,以備后續插入課時")
188 section_type_choices = ((0, '文檔'), (1, '練習'), (2, '視頻'))
189 section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
190
191
192 section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文檔,填link")
193 # vid:cc視頻,唯一標識:sdfsgdfgdgfhgfh
194 video_time = models.CharField(verbose_name="視頻時長", blank=True, null=True, max_length=32) # 僅在前端展示使用
195 pub_date = models.DateTimeField(verbose_name="發布時間", auto_now_add=True)
196 free_trail = models.BooleanField("是否可試看", default=False)
197
198
199 class Meta:
200 unique_together = ('chapter', 'section_link')
201
202
203 def __str__(self):
204 return "%s-%s" % (self.chapter, self.name)
205
206 class Coupon(models.Model):
207 """優惠券生成規則"""
208 name = models.CharField(max_length=64, verbose_name="活動名稱")
209 brief = models.TextField(blank=True, null=True, verbose_name="優惠券介紹")
210 coupon_type_choices = ((0, '通用券'), (1, '滿減券'), (2, '折扣券'))
211 coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券類型")
212
213 money_equivalent_value = models.IntegerField(verbose_name="等值貨幣")
214 off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只針對折扣券,例7.9折,寫79", blank=True, null=True)
215 minimum_consume = models.PositiveIntegerField("最低消費", default=0, help_text="僅在滿減券時填寫此字段")
216
217 content_type = models.ForeignKey(ContentType, blank=True, null=True)
218 object_id = models.PositiveIntegerField("綁定課程", blank=True, null=True, help_text="可以把優惠券跟課程綁定")
219 content_object = GenericForeignKey('content_type', 'object_id')
220
221 quantity = models.PositiveIntegerField("數量(張)", default=1)
222 open_date = models.DateField("優惠券領取開始時間")
223 close_date = models.DateField("優惠券領取結束時間")
224 valid_begin_date = models.DateField(verbose_name="有效期開始時間", blank=True, null=True)
225 valid_end_date = models.DateField(verbose_name="有效結束時間", blank=True, null=True)
226 coupon_valid_days = models.PositiveIntegerField(verbose_name="優惠券有效期(天)", blank=True, null=True,
227 help_text="自券被領時開始算起")
228 date = models.DateTimeField(auto_now_add=True)
229
230 def __str__(self):
231 return "%s(%s)" % (self.get_coupon_type_display(), self.name)
232
233 def save(self, *args, **kwargs):
234 if not self.coupon_valid_days or (self.valid_begin_date and self.valid_end_date):
235 if self.valid_begin_date and self.valid_end_date:
236 if self.valid_end_date <= self.valid_begin_date:
237 raise ValueError("valid_end_date 有效期結束日期必須晚于 valid_begin_date ")
238 if self.coupon_valid_days == 0:
239 raise ValueError("coupon_valid_days 有效期不能為0")
240 if self.close_date < self.open_date:
241 raise ValueError("close_date 優惠券領取結束時間必須晚于 open_date優惠券領取開始時間 ")
242
243 super(Coupon, self).save(*args, **kwargs) 課程相關的13張表 1 # ######################## 深科技相關 ########################2 3 class ArticleSource(models.Model):4 """文章來源"""5 name = models.CharField(max_length=64, unique=True)6 7 def __str__(self):8 return self.name9
10
11 class Article(models.Model):
12 """文章資訊"""
13 title = models.CharField(max_length=255, unique=True, db_index=True, verbose_name="標題")
14 source = models.ForeignKey("ArticleSource", verbose_name="來源")
15 article_type_choices = ((0, '資訊'), (1, '視頻'))
16 article_type = models.SmallIntegerField(choices=article_type_choices, default=0)
17 brief = models.TextField(max_length=512, verbose_name="摘要")
18 head_img = models.CharField(max_length=255)
19 content = models.TextField(verbose_name="文章正文")
20 pub_date = models.DateTimeField(verbose_name="上架日期")
21 offline_date = models.DateTimeField(verbose_name="下架日期")
22 status_choices = ((0, '在線'), (1, '下線'))
23 status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="狀態")
24 order = models.SmallIntegerField(default=0, verbose_name="權重", help_text="文章想置頂,可以把數字調大,不要超過1000")
25 vid = models.CharField(max_length=128, verbose_name="視頻VID", help_text="文章類型是視頻, 則需要添加視頻VID", blank=True, null=True)
26 comment_num = models.SmallIntegerField(default=0, verbose_name="評論數")
27 agree_num = models.SmallIntegerField(default=0, verbose_name="點贊數")
28 view_num = models.SmallIntegerField(default=0, verbose_name="觀看數")
29 collect_num = models.SmallIntegerField(default=0, verbose_name="收藏數")
30
31 tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽")
32 date = models.DateTimeField(auto_now_add=True, verbose_name="創建日期")
33
34 position_choices = ((0, '信息流'), (1, 'banner大圖'), (2, 'banner小圖'))
35 position = models.SmallIntegerField(choices=position_choices, default=0, verbose_name="位置")
36 comment = GenericRelation("Comment") # 用于GenericForeignKey反向查詢, 不會生成表字段,切勿刪除,如有疑問請聯系老村長
37
38 def __str__(self):
39 return "%s-%s" % (self.source, self.title)
40
41
42 class Collection(models.Model):
43 """收藏"""
44 content_type = models.ForeignKey(ContentType)
45 object_id = models.PositiveIntegerField()
46 content_object = GenericForeignKey('content_type', 'object_id')
47
48 account = models.ForeignKey("Account")
49 date = models.DateTimeField(auto_now_add=True)
50
51 class Meta:
52 unique_together = ('content_type', 'object_id', 'account')
53
54
55 # 深科技評論和視頻評論
56 class Comment(models.Model):
57 """通用的評論表: 課程評論 """
58 content_type = models.ForeignKey(ContentType, blank=True, null=True, verbose_name="類型")
59 object_id = models.PositiveIntegerField(blank=True, null=True)
60 content_object = GenericForeignKey('content_type', 'object_id')
61
62 p_node = models.ForeignKey("self", blank=True, null=True, verbose_name="父級評論")
63 content = models.TextField(max_length=1024)
64 account = models.ForeignKey("Account", verbose_name="會員名")
65 disagree_number = models.IntegerField(default=0, verbose_name="踩")
66 agree_number = models.IntegerField(default=0, verbose_name="贊同數")
67 date = models.DateTimeField(auto_now_add=True)
68
69 def __str__(self):
70 return self.content 深科技相關 1 # ######################## 購買課程相關 ########################2 3 class EnrolledCourse(models.Model):4 """已報名課程,不包括學位課程"""5 account = models.ForeignKey("Account")6 course = models.ForeignKey("Course", limit_choices_to=~Q(course_type=2))7 enrolled_date = models.DateTimeField(auto_now_add=True)8 valid_begin_date = models.DateField(verbose_name="有效期開始自")9 valid_end_date = models.DateField(verbose_name="有效期結束至")10 status_choices = ((0, '已開通'), (1, '已過期'))11 status = models.SmallIntegerField(choices=status_choices, default=0)12 order_detail = models.OneToOneField("OrderDetail") # 使訂單購買后支持 課程評價13 14 # order = models.ForeignKey("Order",blank=True,null=True)15 16 def __str__(self):17 return "%s:%s" % (self.account, self.course)18 19 20 class DegreeRegistrationForm(models.Model):21 """學位課程報名表"""22 enrolled_degree = models.OneToOneField("EnrolledDegreeCourse")23 current_company = models.CharField(max_length=64, )24 current_position = models.CharField(max_length=64, )25 current_salary = models.IntegerField()26 work_experience_choices = (27 (0, "應屆生"),28 (1, "1年"),29 (2, "2年"),30 (3, "3年"),31 (4, "4年"),32 (5, "5年"),33 (6, "6年"),34 (7, "7年"),35 (8, "8年"),36 (9, "9年"),37 (10, "10年"),38 (11, "超過10年"),39 )40 work_experience = models.IntegerField()41 open_module = models.BooleanField("是否開通第1模塊", default=True)42 stu_specified_mentor = models.CharField("學員自行指定的導師名", max_length=32, blank=True, null=True)43 study_plan_choices = ((0, "1-2小時/天"),44 (1, "2-3小時/天"),45 (2, "3-5小時/天"),46 (3, "5小時+/天"),47 )48 study_plan = models.SmallIntegerField(choices=study_plan_choices, default=1)49 why_take_this_course = models.TextField("報此課程原因", max_length=1024)50 why_choose_us = models.TextField("為何選路飛", max_length=1024)51 your_expectation = models.TextField("你的期待", max_length=1024)52 memo = models.CharField(max_length=255, blank=True, null=True)53 54 def __str__(self):55 return "%s" % self.enrolled_degree56 57 58 class EnrolledDegreeCourse(models.Model):59 """已報名的學位課程"""60 account = models.ForeignKey("Account")61 degree_course = models.ForeignKey("DegreeCourse")62 enrolled_date = models.DateTimeField(auto_now_add=True)63 valid_begin_date = models.DateField(verbose_name="有效期開始自", blank=True, null=True) # 開通第一個模塊時,再添加課程有效期,2年64 valid_end_date = models.DateField(verbose_name="有效期結束至", blank=True, null=True)65 status_choices = (66 (0, '在學中'),67 (1, '休學中'),68 (2, '已畢業'),69 (3, '超時結業'),70 (4, '未開始'),71 # (3, '其它'),72 )73 study_status = models.SmallIntegerField(choices=status_choices, default=0)74 mentor = models.ForeignKey("Account", verbose_name="導師", related_name='my_students',75 blank=True, null=True, limit_choices_to={'role': 1})76 mentor_fee_balance = models.PositiveIntegerField("導師費用余額", help_text="這個學員的導師費用,每有懲罰,需在此字段同時扣除")77 order_detail = models.OneToOneField("OrderDetail") # 使訂單購買后支持填寫報名表78 79 def __str__(self):80 return "%s:%s" % (self.account, self.degree_course)81 82 class Meta:83 unique_together = ('account', 'degree_course')84 85 86 class Coupon(models.Model):87 """優惠券生成規則"""88 name = models.CharField(max_length=64, verbose_name="活動名稱")89 brief = models.TextField(blank=True, null=True, verbose_name="優惠券介紹")90 coupon_type_choices = ((0, '通用券'), (1, '滿減券'), (2, '折扣券'))91 coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券類型")92 93 money_equivalent_value = models.IntegerField(verbose_name="等值貨幣")94 off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只針對折扣券,例7.9折,寫79", blank=True, null=True)95 minimum_consume = models.PositiveIntegerField("最低消費", default=0, help_text="僅在滿減券時填寫此字段")96 97 content_type = models.ForeignKey(ContentType, blank=True, null=True)98 object_id = models.PositiveIntegerField("綁定課程", blank=True, null=True, help_text="可以把優惠券跟課程綁定")99 content_object = GenericForeignKey('content_type', 'object_id')
100
101 quantity = models.PositiveIntegerField("數量(張)", default=1)
102 open_date = models.DateField("優惠券領取開始時間")
103 close_date = models.DateField("優惠券領取結束時間")
104 valid_begin_date = models.DateField(verbose_name="有效期開始時間", blank=True, null=True)
105 valid_end_date = models.DateField(verbose_name="有效結束時間", blank=True, null=True)
106 coupon_valid_days = models.PositiveIntegerField(verbose_name="優惠券有效期(天)", blank=True, null=True,
107 help_text="自券被領時開始算起")
108 date = models.DateTimeField(auto_now_add=True)
109
110 def __str__(self):
111 return "%s(%s)" % (self.get_coupon_type_display(), self.name)
112
113 def save(self, *args, **kwargs):
114 if not self.coupon_valid_days or (self.valid_begin_date and self.valid_end_date):
115 if self.valid_begin_date and self.valid_end_date:
116 if self.valid_end_date <= self.valid_begin_date:
117 raise ValueError("valid_end_date 有效期結束日期必須晚于 valid_begin_date ")
118 if self.coupon_valid_days == 0:
119 raise ValueError("coupon_valid_days 有效期不能為0")
120 if self.close_date < self.open_date:
121 raise ValueError("close_date 優惠券領取結束時間必須晚于 open_date優惠券領取開始時間 ")
122
123 super(Coupon, self).save(*args, **kwargs)
124
125
126 class CouponRecord(models.Model):
127 """優惠券發放、消費紀錄"""
128 coupon = models.ForeignKey("Coupon")
129 #number = models.CharField(max_length=64, unique=True)
130 account = models.ForeignKey("Account", verbose_name="擁有者")
131 status_choices = ((0, '未使用'), (1, '已使用'), (2, '已過期'),)
132 status = models.SmallIntegerField(choices=status_choices, default=0)
133 get_time = models.DateTimeField(verbose_name="領取時間", help_text="用戶領取時間")
134 used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用時間")
135 order = models.ForeignKey("Order", blank=True, null=True, verbose_name="關聯訂單") # 一個訂單可以有多個優惠券
136
137
138 class Order(models.Model):
139 """訂單"""
140 payment_type_choices = ((0, '微信'), (1, '支付寶'), (2, '優惠碼'), (3, '貝里'))
141 payment_type = models.SmallIntegerField(choices=payment_type_choices)
142 payment_number = models.CharField(max_length=128, verbose_name="支付第3方訂單號", null=True, blank=True)
143 order_number = models.CharField(max_length=128, verbose_name="訂單號", unique=True) # 考慮到訂單合并支付的問題
144 account = models.ForeignKey("Account")
145 actual_amount = models.FloatField(verbose_name="實付金額")
146
147 status_choices = ((0, '交易成功'), (1, '待支付'), (2, '退費申請中'), (3, '已退費'), (4, '主動取消'), (5, '超時取消'))
148 status = models.SmallIntegerField(choices=status_choices, verbose_name="狀態")
149 date = models.DateTimeField(auto_now_add=True, verbose_name="訂單生成時間")
150 pay_time = models.DateTimeField(blank=True, null=True, verbose_name="付款時間")
151 cancel_time = models.DateTimeField(blank=True, null=True, verbose_name="訂單取消時間")
152
153 def __str__(self):
154 return "%s" % self.order_number
155
156
157 class OrderDetail(models.Model):
158 """訂單詳情"""
159 order = models.ForeignKey("Order")
160
161 content_type = models.ForeignKey(ContentType) # 可關聯普通課程或學位
162 object_id = models.PositiveIntegerField()
163 content_object = GenericForeignKey('content_type', 'object_id')
164
165 original_price = models.FloatField("課程原價")
166 price = models.FloatField("折后價格")
167 content = models.CharField(max_length=255, blank=True, null=True) # ?
168 valid_period_display = models.CharField("有效期顯示", max_length=32) # 在訂單頁顯示
169 valid_period = models.PositiveIntegerField("有效期(days)") # 課程有效期
170 memo = models.CharField(max_length=255, blank=True, null=True)
171
172 # def __str__(self):
173 # return "%s - %s - %s" % (self.order, self.content_type, self.price)
174
175 class Meta:
176 # unique_together = ("order", 'course')
177 unique_together = ("order", 'content_type', 'object_id')
178
179
180 class TransactionRecord(models.Model):
181 """貝里交易紀錄"""
182 account = models.ForeignKey("Account")
183 amount = models.IntegerField("金額")
184 balance = models.IntegerField("賬戶余額")
185 transaction_type_choices = ((0, '收入'), (1, '支出'), (2, '退款'), (3, "提現")) # 2 為了處理 訂單過期未支付時,鎖定期貝里的回退
186 transaction_type = models.SmallIntegerField(choices=transaction_type_choices)
187
188 content_type = models.ForeignKey(ContentType, blank=True, null=True)
189 object_id = models.PositiveIntegerField(blank=True, null=True, verbose_name="關聯對象")
190 content_object = GenericForeignKey('content_type', 'object_id')
191
192 transaction_number = models.CharField(unique=True, verbose_name="流水號", max_length=128)
193 date = models.DateTimeField(auto_now_add=True)
194 memo = models.CharField(max_length=128, blank=True, null=True)
195
196 def __str__(self):
197 return "%s" % self.transaction_number 購買課程相關的8張表 1 class Homework(models.Model):2 chapter = models.ForeignKey("CourseChapter")3 title = models.CharField(max_length=128, verbose_name="作業題目")4 order = models.PositiveSmallIntegerField("作業順序", help_text="同一課程的每個作業之前的order值間隔1-2個數")5 homework_type_choices = ((0, '作業'), (1, '模塊通關考核'))6 homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)7 requirement = models.TextField(max_length=1024, verbose_name="作業需求")8 threshold = models.TextField(max_length=1024, verbose_name="踩分點")9 recommend_period = models.PositiveSmallIntegerField("推薦完成周期(天)", default=7)10 scholarship_value = models.PositiveSmallIntegerField("為該作業分配的獎學金(貝里)")11 note = models.TextField(blank=True, null=True)12 enabled = models.BooleanField(default=True, help_text="本作業如果后期不需要了,不想讓學員看到,可以設置為False")13 14 class Meta:15 unique_together = ("chapter", "title")16 17 def __str__(self):18 return "%s - %s" % (self.chapter, self.title)19 20 21 class Teacher(models.Model):22 """講師、導師表"""23 name = models.CharField(max_length=32)24 role_choices = ((0, '講師'), (1, '導師'))25 role = models.SmallIntegerField(choices=role_choices, default=0)26 title = models.CharField(max_length=64, verbose_name="職位、職稱")27 signature = models.CharField(max_length=255, help_text="導師簽名", blank=True, null=True)28 image = models.CharField(max_length=128)29 brief = models.TextField(max_length=1024)30 31 def __str__(self):32 return self.name33 34 35 # 普通課購買課程后,我的訂單中去評價。36 class CourseReview(models.Model):37 """課程評價"""38 enrolled_course = models.OneToOneField("EnrolledCourse")39 about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰")40 about_video = models.FloatField(default=0, verbose_name="內容實用")41 about_course = models.FloatField(default=0, verbose_name="課程內容通俗易懂")42 review = models.TextField(max_length=1024, verbose_name="評價")43 disagree_number = models.IntegerField(default=0, verbose_name="踩")44 agree_number = models.IntegerField(default=0, verbose_name="贊同數")45 tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽")46 date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期")47 is_recommend = models.BooleanField("熱評推薦", default=False)48 hide = models.BooleanField("不在前端頁面顯示此條評價", default=False)49 50 def __str__(self):51 return "%s-%s" % (self.enrolled_course.course, self.review)52 53 54 # 學位課購買課程后,我的訂單中去天報名表,然后就編程去學習(以后去評價)。55 class DegreeCourseReview(models.Model):56 """學位課程評價57 為了以后可以定制單獨的評價內容,所以不與普通課程的評價混在一起,單獨建表58 """59 enrolled_course = models.ForeignKey("EnrolledDegreeCourse")60 course = models.ForeignKey("Course", verbose_name="評價學位模塊", blank=True, null=True,61 help_text="不填寫即代表評價整個學位課程", limit_choices_to={'course_type': 2})62 about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰")63 about_video = models.FloatField(default=0, verbose_name="視頻質量")64 about_course = models.FloatField(default=0, verbose_name="課程")65 review = models.TextField(max_length=1024, verbose_name="評價")66 disagree_number = models.IntegerField(default=0, verbose_name="踩")67 agree_number = models.IntegerField(default=0, verbose_name="贊同數")68 tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽")69 date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期")70 is_recommend = models.BooleanField("熱評推薦", default=False)71 hide = models.BooleanField("不在前端頁面顯示此條評價", default=False)72 73 def __str__(self):74 return "%s-%s" % (self.enrolled_course, self.review)75 76 77 78 # 購買學位課后,為每個學生每個模塊會立刻生成一條學習紀錄(未開通)79 class StudyRecord(models.Model):80 """學位課程的模塊學習進度81 報名學位課程后,每個模塊會立刻生成一條學習紀錄82 """83 enrolled_degree_course = models.ForeignKey("EnrolledDegreeCourse")84 course_module = models.ForeignKey("Course", verbose_name="學位模塊", limit_choices_to={'course_type': 2})85 open_date = models.DateField(blank=True, null=True, verbose_name="開通日期")86 end_date = models.DateField(blank=True, null=True, verbose_name="完成日期")87 status_choices = ((2, '在學'), (1, '未開通'), (0, '已完成'))88 status = models.SmallIntegerField(choices=status_choices, default=1)89 90 class Meta:91 unique_together = ('enrolled_degree_course', 'course_module')92 93 def __str__(self):94 return '%s-%s' % (self.enrolled_degree_course, self.course_module)95 96 def save(self, *args, **kwargs):97 if self.course_module.degree_course_id != self.enrolled_degree_course.degree_course_id:98 raise ValueError("學員要開通的模塊必須與其報名的學位課程一致!")99
100 super(StudyRecord, self).save(*args, **kwargs)
101
102
103 # 為學生開通一個模塊
104 class CourseSchedule(models.Model):
105 """課程進度計劃表,針對學位課程,每開通一個模塊,就為這個學員生成這個模塊的推薦學習計劃表,后面的獎懲均按此表進行"""
106 study_record = models.ForeignKey("StudyRecord")
107 homework = models.ForeignKey("Homework")
108 recommend_date = models.DateField("推薦交作業日期")
109
110 def __str__(self):
111 return "%s - %s - %s " % (self.study_record, self.homework, self.recommend_date)
112
113 class Meta:
114 unique_together = ('study_record', 'homework')
115
116
117 # 學生交作業
118 class HomeworkRecord(models.Model):
119 """學員作業記錄及成績"""
120 homework = models.ForeignKey("Homework")
121 student = models.ForeignKey("EnrolledDegreeCourse", verbose_name="學生")
122 score_choices = (
123 (100, 'A+'),
124 (90, 'A'),
125 (85, 'B+'),
126 (80, 'B'),
127 (70, 'B-'),
128 (60, 'C+'),
129 (50, 'C'),
130 (40, 'C-'),
131 (-1, 'D'),
132 (0, 'N/A'),
133 (-100, 'COPY'),
134 )
135 score = models.SmallIntegerField(verbose_name="分數", choices=score_choices, null=True, blank=True)
136 mentor = models.ForeignKey("Account", related_name="my_stu_homework_record", limit_choices_to={'role': 1},
137 verbose_name="導師")
138 mentor_comment = models.TextField(verbose_name="導師批注", blank=True, null=True) # 導師
139 status_choice = (
140 (0, '待批改'),
141 (1, '已通過'),
142 (2, '不合格'),
143 )
144 status = models.SmallIntegerField(verbose_name='作業狀態', choices=status_choice, default=0)
145
146 submit_num = models.SmallIntegerField(verbose_name='提交次數', default=0)
147 correct_date = models.DateTimeField('備注日期', blank=True, null=True)
148 note = models.TextField(blank=True, null=True)
149 date = models.DateTimeField("作業提交日期", auto_now_add=True)
150
151 check_date = models.DateTimeField("批改日期", null=True, blank=True)
152
153 update_time = models.DateTimeField(auto_now=True, verbose_name="提交日期")
154
155 # homework_path = models.CharField(verbose_name='作業路徑', max_length=256,blank=True,null=True) 作業路徑可以動態拿到,沒必要存
156
157 reward_choice = (
158 (0, '新提交'),
159 (1, '按時提交'),
160 (2, '未按時提交'),
161 (3, '成績已獎勵'),
162 (4, '成績已處罰'),
163 (5, '未作按時檢測'),
164 )
165 reward_status = models.SmallIntegerField(verbose_name='作業記錄獎懲狀態', default=0)
166
167 def __str__(self):
168 return "%s %s" % (self.homework, self.student)
169
170 class Meta:
171 unique_together = ("homework", "student")
172
173
174 # 導師跟進記錄
175 class StuFollowUpRecord(models.Model):
176 """學員跟進記錄"""
177 enrolled_degree_course = models.ForeignKey("EnrolledDegreeCourse", verbose_name="學生")
178 mentor = models.ForeignKey("Account", related_name='mentor', limit_choices_to={'role': 1}, verbose_name="導師")
179 followup_tool_choices = ((0, 'QQ'), (1, '微信'), (2, '電話'), (3, '系統通知'))
180 followup_tool = models.SmallIntegerField(choices=followup_tool_choices, default=1)
181 record = models.TextField(verbose_name="跟進記錄")
182 attachment_path = models.CharField(max_length=128, blank=True, null=True, verbose_name="附件路徑", help_text="跟進記錄的截圖等")
183 date = models.DateTimeField(auto_now_add=True)
184
185 def __str__(self):
186 return "%s --%s --%s" % (self.enrolled_degree_course, self.record, self.date) 學位課優惠相關的表 ?
轉載于:https://www.cnblogs.com/morgana/p/8496399.html
總結
以上是生活随笔為你收集整理的K12(在线学习的平台)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最贵的烟多少钱一包啊?
- 下一篇: 为什么机械表的价值高?