Текущая схема таблицы:
User
- id
- default_handling_fee(integer, null=True)
Order
- id
- buyer(user_id)
- order_handling_fee(integer, null=True)
Теперь мы хотим добавить второй тип комиссии, которая может применяться к заказам. Некоторые правила:
- Сборы распространяются на <10% заказов. </li>
- Заказ может иметь либо 0, либо обе комиссии.
- Каждый раз, когда информация о заказе отображается пользователям, нам нужно выделять сборы и указывать виды сборов.
- Сборы должны редактироваться в зависимости от заказа.
- Мы можем добавить дополнительные сборы в будущем.
- База данных в настоящее время довольно мала (несколько тысяч строк) и вряд ли вырастет за пределы 100 000 в следующие несколько лет.
Я вижу два варианта:
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, добавить новую «таблицу сборов»:
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 (новая таблица) мы сначала будем искать существующие комиссии, которые соответствуют пользователю и цене. Если такая комбинация существует, мы добавим ее в поле order_fees
. Если бы он не существовал (новая цена), мы создали бы новую строку и добавили бы эту строку в поле order_fees
.
Я признаю, что вариант 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 в качестве бэкэнда, мы можем определить методы для модели так, чтобы все поля цены были определены в одном месте.
Какие вариант лучше? Есть ли третий вариант, который я не рассматривал?
(отредактировано для ясности)