I empfehlen Verwendung von Relationen und Denormalisierung sólo wenn Sie Leistungsprobleme haben und sólo nachdem Sie bestätigt haben, dass diese schlechte Leistung mit der Abfrage des Kategorienamens zusammenhängt. Andernfalls wird die Sache nur noch komplizierter, ohne dass es dafür einen guten Grund gibt. Behalten Sie im Hinterkopf Donald Knuths berühmtes Zitat:
Vorzeitige Optimierung ist die Wurzel allen Übels.
Relationale Datenbanken sind gut für Joins, denn dafür wurden sie entwickelt. In dem von Ihnen gewünschten denormalisierten Design werden statt der einfachst möglichen JOINs
benötigen Sie komplexe UPDATEs
. Diese Aktualisierungen betreffen viele Zeilen in vielen (10-20) Tabellen. Wenn Sie viele Daten in den betroffenen Tabellen haben und häufig den Kategorie-Namen ändern, kann/ wird sich die Leistung sogar verschlechtern.
Wenn Sie sich wirklich mit der Idee anfreunden können category_name
in 10-20 Tabellen die Verwendung eines Datenbanktrigger . Der Trigger wird ausgeführt, wenn eine Kategorietabelle geändert wird. Er kann alle Aktualisierungen intern in der Datenbank verarbeiten. Ohne etwas in Ihrem Django-Projekt zu ändern und mit weniger Overhead.
Wenn Sie sich also wirklich mit der Idee anfreunden können category_name
in 10-20 Tabellen und Sie kann nicht Auslöser zu verwenden, gibt es einen Mechanismus namens Signale in Django. Dies sind eine Art Trigger, die in Django eingebettet sind und vor/nach einem definierten Ereignis ausgelöst werden.
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)