2008-10-27 24 views
6

Mam dość ogólny model artykułu, z relacji m2m do modelu Tag. Chcę zachować licznik każdego użycia znacznika, myślę, że najlepszym sposobem byłoby denormalizacja pola licznika w modelu Tag i zaktualizowanie go za każdym razem, gdy artykuł zostanie zapisany. Jak mogę to osiągnąć, a może jest lepszy sposób?sygnał post_save na m2m polu

Odpowiedz

2

Można to zrobić poprzez stworzenie intermediate model dla relacji M2M i używać go jako haczyk na sygnały post_save i post_delete zaktualizować kolumnę denormalised w tabeli Article.

Na przykład, robię to dla favourited Question liczy w soclone, gdzie User s mają związek M2M z 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')) 

Nie było trochę dyskusji na django-programistów liście dyskusyjnej o wdrażaniu środkiem deklaratywnie deklarujących denormalisations aby uniknąć konieczności pisania kodu jak wyżej:

+0

Nie ma haczyka z tej techniki jednak: jeśli chcesz korzystać z tych klas w formie, będzie form.save_m2m przestanie działać – Rob

3
+2

Uważaj jednak na sygnał m2m_changed, ponieważ nie ma możliwości dowiedzenia się, co dokładnie zmieniło się w treserze. –

+0

Czy nie wysyła argumentu akcji? –

+0

Zasadniczo wiesz, jaki jest obecny stan, ale nie masz możliwości dowiedzenia się, jaki był stan przed wysłaniem sygnału. W przypadku podanym w pytaniu oryginalnym wystarczy znać tylko liczbę załączników, więc jest to w porządku. –

Powiązane problemy