2 Stimmen

Django Denormalisierung und Konsistenz

Ich bin nicht sicher, wie man Denormalisierung in Django zu tun. Wie pro mir ich denke an so etwas wie dieses zu tun:

Ich habe 2 Modelle:

Kategorie:

 name = m.CharField(max_length = 127)

Artikel:

 name = m.CharField(max_length = 127)
 category = m.ForeignKey(Category)
 category_name = m.CharField(max_length = 127)

Ich möchte, dass dies geschieht:

Wenn ich den Namen einer Kategorie ändere, werden die Änderungen in allen Artikeln berücksichtigt. Was ist nun die beste Vorgehensweise, wenn wir nicht nur ein oder zwei Felder haben, sondern etwa 10-20, die synchronisiert werden müssen?

7voto

Mariusz Jamro Punkte 28908

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)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X