sinal post_save no campo M2M
-
04-07-2019 - |
Pergunta
Eu tenho um modelo de artigo bastante genérico, com a relação M2M com o modelo de tag. Quero manter a contagem de cada uso de tags, acho que a melhor maneira seria desnormar o campo de contagem de tags e atualizá -lo cada vez que o artigo sendo salvo. Como posso conseguir isso, ou talvez haja uma maneira melhor?
Solução
Você pode fazer isso criando um modelo intermediário para o relacionamento M2M e use -o como seu gancho para o post_save
e post_delete
sinaliza para atualizar a coluna desnormalizada no Article
tabela.
Por exemplo, eu faço isso para favoritos Question
conta em Soclone, Onde User
s ter um relacionamento M2M com 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'))
Houve um pouco de discussão sobre a lista de discussão dos desenvolvedores de Django sobre a implementação de um meio de declarar declarar declarar as desnormalizações para evitar ter que escrever código como o acima:
Outras dicas
Este é um novo recurso no Django 1.2:http://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed