表结构
# 表分析
# -- 用户相关的表
用户分为管理员和客户. 针对管理员和客户,初步想到了两种设计方案.
1.将管理员和客户拆分到两张表中
2.将管理员和客户放到一张表中
[思考]:
若管理员和客户里面所需要的字段都是一样的,比如都只有username、password、mobile这三个字段,那我们一般将其放到同一张表里.
User用户表 -- username、password、mobile、user_type
"""
# -- 放到一张表里,通过user_type字段进行区分 1/管理员; 2/客户
user_type = models.SmallIntegerField(verbose_name="用户类型")
"""
但如果管理员和客户里面有些字段不同,不同的还挺多的,那么就不应该放到一张表里.
比如:就订单系统而言,管理员是不分级别的,客户是分级别的,级别不同,折扣不同.
So,我们应该选择第一种设计方案!!
# -- 该字段的值不用传
# -- auto_now=True表明创建和更新该表中的数据时,会<自动>添加/更新时间日期为当前时间!
# -- 若只需在创建的时候,<自动>保存一个创建日期,设置auto_now_add=True
create_date = models.DateTimeField(verbose_name="创建日期", auto_now_add=True)
# -- 该字段是为了实现对管理员、用户等的逻辑删除,而不是物理删除!!
# -- 1/激活; 2/已删除
# -- active字段值"在数据库中"是int类型.. choices字段属性设置的对应关系"是放在内存中的",可以取到该字段值对应的中文意思!!
active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))
"""
data = Administrator.object.all() # Administrator管理员表
for obj in data:
data.active # 获取在数据库中存储的int类型的值
data.get_active_display() # 获取到对应的中文!!
"""
# -- 需要进行逻辑删除的表,都可以加上该字段,但可以做优化!
"""
class ActiveBaseModel(models.Model): # 做基类,为子类提供统一的额外字段!!
active = models.SmallIntegerField(verbose_name="状态", default=1, choices=((1, "激活"), (0, "删除"),))
class Meta:
abstract = True # 使得Django不会在数据库中生成该类对应的表
class Administrator(ActiveBaseModel):
pass
"""
[思考]:
若客户的级别是固定的,比如级别确定只有 vip、vvip、svip三个级别.适合如此创建.
"""
level_choices = (
(1,'vip'),
(2,'vvip'),
(3,'svip'),
)
active = models.SmallIntegerField(verbose_name="级别", default=1, choices=level_choices)
"""
若客户的级别经常变动,有时候删除一个级别,有时候添加一个级别.那么得为级别单独创建一张表!!
该订单系统中,为级别单独创建了一张表.
[思考]:
对价格策略表的分析
相当于原价,比如, 1000的播放量/5元;2000的播放量/8元.. 播放量越高,单价越低
在原价的基础上再根据客户的级别打折.
若不想有价格策略,就单条多少钱,该表内只生成一条记录即可.
我们想让该表物理删除.那就直接删除呗!
[思考]:
对订单表的分析
1> 订单应具备四个状态, 待执行、正在执行、已完成、失败
2> 按理说,订单表有状态、订单号、视频地址、订单数量,就可以啦.但下单的数量不同,根据价格策略算出来的价格也不同.
那么,price = models.ForeignKey(verbose_name="原价",to="PricePolicy") 订单表与价格策略表相关联.
假设订单为2000条,命中了2000的播放量/8元这条策略. 则订单表中的price的值为2. 可?
逻辑方案可行,但欠考虑,万一,我id为2的价格策略变了呢?8元变成了10元,以后查看订单就跟当时查看的订单,帐就对不上了.
我们应该根据当时的价格策略,算出来多少钱就存储多少,不必做外键关联!!
3> 除了根据价格策略得到的原价,还有再根据客户级别算出来的金额/实际价格,同理.算出来多少钱就存储多少.
(客户今天的级别跟明天的级别可能不同,客户的级别也可能动态变化!!)
4> 订单表的其它字段,哪个客户下的单、该订单可以有备注信息、创建日期
5> 想让客户直观的看到下单之前播放量是多少,跑完后,视频的播放量是多少. 可以加个字段,old_view_count原播放量是多少.
old_view_count = models.CharField(verbose_name="原播放量", max_length=32, default="0")
播放量是个数字,为啥用CharField呢?
我们去平台上获取视频播放量,若<10000,eg:"9900";若>10000,eg:"2.3w"
当然,我们可以做一个转换.但没必要,懒.
6> 有原播放量,是否要加一个字段new_view_count表示最新播放量? no!
原因:刷完播放量后不是实时的去涨,可能会等10~20min后才会涨. 所以,要获得最新的,还得做个定时任务去获取.比较费劲.
客户想看最新播放量,自己点击url跳转过去看.
[思考]:
对交易记录表的分析
1> 为什么需要交易记录表呢?因为先要给客户充值,然后客户再去消费.
2> 交易记录有5个类型: 充值、扣款、创建订单、删除订单、撤单
- 哪个管理员给哪个客户在什么时间充值了多少钱. --> 得与客户、管理员相关联
- 因为客户一些违法操作,给他扣款.一般是不会进行扣款的.
- 在客户下单的时候,也得创建个交易记录,记录下
- 创建订单后,订单若还没有执行,可以撤掉订单
- 若删除订单,表明该订单不再显示了
3> 创建订单、删除订单、撤单 需要与订单相关联
order = models.ForeignKey(verbose_name="订单",to="Order",on_delete=models.CASCADE,null=True,blank=True)
但这里没有这么做,外键默认关联的是主键,产生订单后,会有个订单号.更好的选择是将订单号写在这!!在页面中展示时,展示订单号就行.
订单详情呢?根据订单号去查询即可..
order_oid = models.CharField(verbose_name="订单号", max_length=64, null=True, blank=True, db_index=True)
4> 管理员给客户充值是没有订单号的;客户自己下单时才会有订单号,会进行扣费.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 表设计
注意: 我们是基于 文件的方式设计的菜单和权限.. 若是基于数据库的,还得多创建几张表!
ActiveBaseModel基表
active SmallIntegerField default=1, choices=((1, "激活"), (0, "删除"),)
class Meta:
abstract = True
Administrator(ActiveBaseModel)管理员表
username CharField max_length=32,db_index=True
password CharField max_length=64
mobile CharField max_length=11,db_index=True
create_date DateTimeField auto_now_add=True # 创建日期
Customer(ActiveBaseModel)客户表
username CharField max_length=32,db_index=True
password CharField max_length=64
mobile CharField max_length=11,db_index=True
balance DecimalField default=0,max_digits=10,decimal_places=2 # 客户下单,有账户余额
level ForeignKey to="Level",on_delete=models.CASCADE
# 表明客户是哪个管理员创建的,因为该订单系统使用的是邀请制,谁邀请的谁来创建.
creator ForeignKey to="Administrator", on_delete=models.CASCADE
create_date DateTimeField auto_now_add=True # 创建日期
Level(ActiveBaseModel)级别表
title CharField max_length=32
percent IntegerField # 折扣,写80代表8折,90代表9折.
PricePolicy(models.Model)价格策略表
count IntegerField
price DecimalField max_digits=10, decimal_places=2
Order(ActiveBaseModel)订单表
status_choices = ((1, "待执行"),(2, "正在执行"),(3, "已完成"),(4, "失败"),(4, "已撤单"))
status SmallIntegerField choices=status_choices,default=1
oid CharField max_length=64,unique=True # 生成一个唯一的订单号
url URLField db_index=True # 下单视频的地址
count IntegerField # 下单的数量
price DecimalField default=0,max_digits=10,decimal_places=2
real_price DecimalField default=0,max_digits=10,decimal_places=2
old_view_count CharField max_length=32, default="0" # 原播放量
customer ForeignKey to="Customer", on_delete=models.CASCADE # 哪个客户下的单
memo TextField null=True, blank=True # 该订单可以有备注信息
create_date DateTimeField auto_now_add=True # 创建日期
TransactionRecord(ActiveBaseModel)交易记录表
# -- 从数据库中拿到交易记录后,使得不同的类型的交易记录用不同的颜色在前端进行展示
charge_type_class_mapping = {
1: "success",
2: "danger",
3: "default",
4: "info",
5: "primary",
}
charge_type_choices = ((1, "充值"), (2, "扣款"), (3, "创建订单"), (4, "删除订单"), (5, "撤单"),)
charge_type SmallIntegerField choices=charge_type_choices
# 哪个管理员给客户充的值,但客户自己下单就不需要管理员啦,所以该字段可以为空
creator ForeignKey to="Administrator",on_delete=models.CASCADE,null=True,blank=True
customer ForeignKey to="Customer", on_delete=models.CASCADE # 哪个客户下的单
amount DecimalField default=0,max_digits=10,decimal_places=2 # 金额 下单多少钱/充值多少钱
order_oid CharField max_length=64, null=True, blank=True, db_index=True # 订单号
memo TextField null=True, blank=True # 备注
create_date DateTimeField auto_now_add=True # 交易时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66