I рекомендую с использованием отношений и денормализации только , если у вас есть проблемы с производительностью и только после того, как вы подтвердили, что эта плохая производительность связана с запросом имени категории.В противном случае это просто сложность без веской причины.Имейте в виду знаменитая цитата Дональда Кнута:
Преждевременная оптимизация - корень всего зла.
Реляционные базы данных хороши при объединениях, потому что в основномэто то, для чего они были созданы.В денормализованном дизайне, который вы хотите, вместо самого простого JOINs
вам понадобится комплекс UPDATEs
.Эти обновления будут влиять на множество строк во многих (10-20) таблицах.Если у вас есть много данных в затронутых таблицах и вы часто меняете имя_категории, это может / даже ухудшит производительность.
Если вы действительно застряли с идеей category_name
в 10-20 таблицах, рассмотрите возможность использования триггера базы данных .Триггер будет выполнен при изменении таблицы категорий.Он может обрабатывать все обновления внутри базы данных.Не изменяя ничего в вашем проекте Django и с меньшими накладными расходами.
Так что, если вы действительно застряли с идеей category_name
в 10-20 таблицах и вы не можете использовать триггерыв Django есть механизм, называемый сигналов .Это триггеры, встроенные в Django и запускаемые до / после определенного события.
from django.db.models import signals
from django.core.exceptions import DatabaseError
class Category(m.Model):
def __init__(self, *args, **kwargs):
super(Category, self).__init__(*args, **kwargs)
# Store the initial name
self._name = self.name
name = m.CharField(max_length = 127)
def update_category_name(sender, instance, **kwargs):
""" Callback executed when Category is about to be saved """
old_category = instance._name
new_category = instance.name
if old_category != new_category: # Name changed
# Start a transaction ?
try:
# Update the data:
# Make category_name an db_index, otherwise it will be slooooooooow
Article.objects.filter(category_name=old_category).update(category_name=new_category)
# commit transaction ?
except DatabaseError as e:
# rollback transaction ?
# prevent saving the category as database will be inconsistent
raise e
# Bind the callback to pre_save singal
signals.pre_save.connect(update_category_name, sender=Category)