2008-10-27 21 views
6

Tengo un modelo de artículo bastante genérico, con relación m2m al modelo Tag. Quiero contar el uso de cada etiqueta, creo que la mejor manera sería desnormalizar el campo de conteo en el modelo de etiqueta y actualizarlo cada vez que se guarde el artículo. ¿Cómo puedo lograr esto, o tal vez hay una mejor manera?señal post_save en el campo m2m

Respuesta

2

Usted puede hacer esto mediante la creación de un intermediate model para la relación M2M y utilizarlo como su gancho para las señales post_save y post_delete para actualizar la columna desnormalizaremos en la tabla Article.

Por ejemplo, hago esto por Favorecido Question cuenta en soclone, donde User s tienen una relación M2M con 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')) 

Ha habido un poco de discusión sobre los django-desarrolladores lista de correo sobre la implementación un medio de denormalisations declarativa declaran para evitar tener que escribir el código como el de arriba:

+0

Hay una Gotcha con esta técnica sin embargo: si desea utilizar estas clases en una forma, form.save_m2m ya no funcionará – Rob

3

Ésta es una nueva característica de Django 1.2: http://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed

+2

Sin embargo, ten cuidado con la señal m2m_changed porque no hay forma de saber qué ha cambiado exactamente dentro del controlador. –

+0

¿No envía un argumento de acción? –

+0

Básicamente, sabes cuál es el estado actual, pero no tienes forma de saber cuál era el estado antes de enviar la señal. Sin embargo, en el caso dado por la pregunta original, solo necesita saber la cantidad de archivos adjuntos, por lo que está bien. –

Cuestiones relacionadas