2008-10-27 5 views
6

J'ai un modèle d'article assez générique, avec m2m par rapport au modèle Tag. Je veux garder le compte de chaque utilisation de tag, je pense que le meilleur moyen serait de dénormaliser le champ de compte sur le modèle de Tag et de le mettre à jour chaque fois que l'article est enregistré. Comment puis-je accomplir cela, ou peut-être y a-t-il un meilleur moyen?post_save signal sur m2m champ

Répondre

2

Vous pouvez le faire en créant un intermediate model pour la relation M2M et l'utiliser comme votre crochet pour les post_save et post_delete signaux pour mettre à jour la colonne dénormalisé dans le tableau Article.

Par exemple, je fais cela pour Favourited Question compte dans soclone, où User s ont une relation M2M avec Question s:

from django.contrib.auth.models import User 
from django.db import connection, models, transaction 
from django.db.models.signals import post_delete, post_save 

class Question(models.Model): 
    # ... 
    favourite_count = models.PositiveIntegerField(default=0) 

class FavouriteQuestion(models.Model): 
    question = models.ForeignKey(Question) 
    user  = models.ForeignKey(User) 

def update_question_favourite_count(instance, **kwargs): 
    """ 
    Updates the favourite count for the Question related to the given 
    FavouriteQuestion. 
    """ 
    if kwargs.get('raw', False): 
     return 
    cursor = connection.cursor() 
    cursor.execute(
     'UPDATE soclone_question SET favourite_count = (' 
      'SELECT COUNT(*) from soclone_favouritequestion ' 
      'WHERE soclone_favouritequestion.question_id = soclone_question.id' 
     ') ' 
     'WHERE id = %s', [instance.question_id]) 
    transaction.commit_unless_managed() 

post_save.connect(update_question_favourite_count, sender=FavouriteQuestion) 
post_delete.connect(update_question_favourite_count, sender=FavouriteQuestion) 

# Very, very naughty 
User.add_to_class('favourite_questions', 
        models.ManyToManyField(Question, through=FavouriteQuestion, 
             related_name='favourited_by')) 

Il y a eu un peu de discussion sur les développeurs django-liste de diffusion à propos de la mise en œuvre un moyen de déclarer déclarative denormalisations pour éviter d'avoir à écrire du code comme ci-dessus:

+0

Il y a une chasse aux sorcières avec cette technique si: si vous voulez utiliser ces classes sous une forme, form.save_m2m ne fonctionnera plus – Rob

3

Ceci est une nouvelle fonctionnalité de Django 1.2: http://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed

+2

Attention cependant au signal m2m_changed car il n'y a aucun moyen de savoir exactement ce qui a changé dans le gestionnaire. –

+0

N'envoie-t-il pas un argument d'action? –

+0

Fondamentalement, vous savez quel est l'état actuel, mais vous n'avez aucun moyen de savoir quel était l'état avant l'envoi du signal. Dans le cas donné par la question originale cependant, vous avez seulement besoin de connaître le nombre de pièces jointes, donc c'est bien. –

Questions connexes