señal post_save en campo m2m
-
04-07-2019 - |
Pregunta
Tengo un modelo de artículo bastante genérico, con relación m2m al modelo de etiqueta. Quiero seguir contando el uso de cada etiqueta, creo que la mejor manera sería desnormalizar el campo de recuento 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?
Solución
Puede hacer esto creando un modelo intermedio para la relación M2M y utilícelo como gancho para las señales post_save
y post_delete
para actualizar la columna desnormalizada en el Tabla Article
.
Por ejemplo, hago esto para los recuentos favoritos de Question
en soclone , donde User
s tiene 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'))
Se ha discutido un poco en la lista de correo de django-developers sobre la implementación de un medio de declaración declarativa de desnormalizaciones para evitar tener que escribir código como el anterior:
Otros consejos
Esta es una nueva característica en Django 1.2: http://docs.djangoproject.com/en/dev/ref / señales / # m2m-cambiado