数据库:订单属性的新 table 或新字段
Database: new table or new field for order attributes
当前 table 架构:
User
- id
- default_handling_fee(integer, null=True)
Order
- id
- buyer(user_id)
- order_handling_fee(integer, null=True)
我们现在想添加第二种适用于订单的费用。一些规则:
- 费用适用于 < 10% 的订单。
- 一个订单可以有 0 个费用,其中一个或两个。
- 每次向用户显示订单信息时,我们需要
突出显示费用并显示费用类型。
- 费用必须按订单进行编辑table。
- 我们以后可能会增加额外费用。
- 数据库目前很小(几千行)而且不太可能
在未来几年内增长超过 100k。
我可以看到两个选项:
A:在订单上添加一个新字段,在用户上添加一个:
User
- id
- default_handling_fee(integer, null=True)
- default_processing_fee(integer, null=True)
Order
- id
- buyer(user_id)
- order_handling_fee(integer, null=True)
- order_processing_fee(integer, null=True)
或者B,添加一个新的'fees table':
User
- id
Order
- id
- buyer(user_id)
- order_fees(many_to_many_field to OrderFees)
OrderFees
- id
- buyer(user_id)
- price(integer)
- fee_type(choices=['handling', 'processing'])
- is_default_value(boolean)
如果用户创建订单并应用其中一项或两项费用,在选项 B(新 table)中,我们将首先查找与用户和价格相匹配的现有费用。如果该组合存在,我们会将其添加到 order_fees
字段。如果它不存在(新价格),我们将创建一个新行并将该行添加到 order_fees
字段。
我认识到选项 A 简单得多:在查找费用时没有连接,没有创建新行,没有创建一次就不再使用的陈旧行。
我看到 A 的两个缺点。首先,它不可扩展。如果我们在几个月后添加一个 gift_wrapping_fee
,这将意味着在几乎每个订单上添加第三个字段为 null,依此类推以增加其他类型的订单费用。第二个缺点是我们必须记住在显示订单信息的每个地方添加应用内检查。
if order.order_processing_fee:
show fee
if order.order_handling_fee:
show fee
选项B,就是
for fee in order.order_fees:
show fee
选项 B 中出现错误的可能性要小得多,代价是向用户显示每个订单至少一个额外的查询。
另外一点:由于这一切都是使用 Django 作为后端完成的,我们可以在模型上定义方法,以便在一个地方定义所有价格字段。
哪个选项更好?有没有我没有考虑过的第三种选择?
(为清楚起见进行了编辑)
我认为如果在不久的将来您需要添加新的费用类型,那么 B 选项更好。
您是否考虑过 A 和 B 的混合方案?如果我理解这个问题,您不仅要支付订单费用,还要支付用户的默认费用。
您可以收取费用 table:
Fees
-id
-type(choices=[your fee type list])
-price
...(other attributes)
然后你可以有两个多对多关系,一个用于订单
Order
-id
-buyer(user)
-order_fees(many to many)
还有一秒钟给用户
User
-id
-default_fees(many to many)
当前 table 架构:
User
- id
- default_handling_fee(integer, null=True)
Order
- id
- buyer(user_id)
- order_handling_fee(integer, null=True)
我们现在想添加第二种适用于订单的费用。一些规则:
- 费用适用于 < 10% 的订单。
- 一个订单可以有 0 个费用,其中一个或两个。
- 每次向用户显示订单信息时,我们需要 突出显示费用并显示费用类型。
- 费用必须按订单进行编辑table。
- 我们以后可能会增加额外费用。
- 数据库目前很小(几千行)而且不太可能 在未来几年内增长超过 100k。
我可以看到两个选项:
A:在订单上添加一个新字段,在用户上添加一个:
User
- id
- default_handling_fee(integer, null=True)
- default_processing_fee(integer, null=True)
Order
- id
- buyer(user_id)
- order_handling_fee(integer, null=True)
- order_processing_fee(integer, null=True)
或者B,添加一个新的'fees table':
User
- id
Order
- id
- buyer(user_id)
- order_fees(many_to_many_field to OrderFees)
OrderFees
- id
- buyer(user_id)
- price(integer)
- fee_type(choices=['handling', 'processing'])
- is_default_value(boolean)
如果用户创建订单并应用其中一项或两项费用,在选项 B(新 table)中,我们将首先查找与用户和价格相匹配的现有费用。如果该组合存在,我们会将其添加到 order_fees
字段。如果它不存在(新价格),我们将创建一个新行并将该行添加到 order_fees
字段。
我认识到选项 A 简单得多:在查找费用时没有连接,没有创建新行,没有创建一次就不再使用的陈旧行。
我看到 A 的两个缺点。首先,它不可扩展。如果我们在几个月后添加一个 gift_wrapping_fee
,这将意味着在几乎每个订单上添加第三个字段为 null,依此类推以增加其他类型的订单费用。第二个缺点是我们必须记住在显示订单信息的每个地方添加应用内检查。
if order.order_processing_fee:
show fee
if order.order_handling_fee:
show fee
选项B,就是
for fee in order.order_fees:
show fee
选项 B 中出现错误的可能性要小得多,代价是向用户显示每个订单至少一个额外的查询。
另外一点:由于这一切都是使用 Django 作为后端完成的,我们可以在模型上定义方法,以便在一个地方定义所有价格字段。
哪个选项更好?有没有我没有考虑过的第三种选择?
(为清楚起见进行了编辑)
我认为如果在不久的将来您需要添加新的费用类型,那么 B 选项更好。
您是否考虑过 A 和 B 的混合方案?如果我理解这个问题,您不仅要支付订单费用,还要支付用户的默认费用。
您可以收取费用 table:
Fees
-id
-type(choices=[your fee type list])
-price
...(other attributes)
然后你可以有两个多对多关系,一个用于订单
Order
-id
-buyer(user)
-order_fees(many to many)
还有一秒钟给用户
User
-id
-default_fees(many to many)