2011-11-04 3 views
1

Comme je suis assez nouveau dans Django, je demande ici une petite suggestion pour les meilleures pratiques pour faire de la dénormalisation dans Django. Selon moi, je pense à faire quelque chose comme ceci:Django dénormalisation et consistance:

J'ai 2 modèles:

Catégorie:

name = m.CharField(max_length = 127) 

Articles:

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

Je voudrais que cela se produise :

Lorsque je change le nom d'une catégorie pour refléter les modifications dans tous les articles. Maintenant, quelle est vraiment la meilleure pratique quand nous n'avons pas seulement un ou deux champs mais environ 10-20 pour rester synchronisés?

Merci pour votre aide (:

+0

Cela semble être un cas étrange de dénormalisation. Pourquoi pensez-vous que vous en avez besoin? Êtes-vous sûr d'avoir un goulot d'étranglement pour obtenir les informations sur la catégorie? –

+0

Si je devais montrer une liste d'articles avec leur marque, je devrais faire une jointure interne. Dans ce cas je n'aurais besoin d'aucune jointure ... –

+2

C'est évidemment vrai, mais qu'est-ce qui ne va pas avec une jointure? Les bases de données sont bonnes dans ces domaines. La dénormalisation est seulement nécessaire si vous avez déterminé que vous avez définitivement un problème de performance à ce moment-là. –

Répondre

5

Je recommandons en utilisant les relations et dénormaliser que si vous avez des problèmes de performance et seulement après avoir confirmé que cette mauvaise performance est liée à l'interrogation du nom de la catégorie Dans le cas contraire. il est juste d'ajouter la complexité sans une bonne raison Gardez à l'esprit Donald Knuth's célèbre citation:..

l'optimisation prématurée est la racine de tous les maux

Les bases de données relationnelles sont bonnes dans les jointures, car c'est ce à quoi elles ont été conçues. Dans le design dénormalisé que vous voulez, au lieu de la plus simple possible, vous aurez besoin UPDATEs complexe. Ces mises à jour affecteront de nombreuses lignes dans de nombreuses tables (10-20). Si vous avez beaucoup de données dans les tables affectées et que vous modifiez souvent le nom de la catégorie, cela pourrait même aggraver les performances.


Si vous êtes vraiment coincé avec l'idée de category_name à 10-20 tables envisager d'utiliser un database trigger. Le déclencheur sera exécuté quand une table de catégorie est changée. Il peut gérer toutes les mises à jour en interne dans la base de données. Sans rien changer dans votre projet Django et avec moins de frais généraux.

Donc, si vous êtes vraiment coincé avec l'idée de category_name dans 10-20 tables et vous ne pouvez pas utiliser des déclencheurs, il y a un mécanisme appelé signals dans Django. Ce sont des sortes de déclencheurs intégrés dans Django et déclenchés avant/après un événement défini.

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) 
Questions connexes