signal post_save sur le champ m2m
-
04-07-2019 - |
Question
J'ai un joli modèle d'article générique, avec une relation m2m avec le modèle Tag. Je veux garder le compte de chaque utilisation de balise, je pense que le meilleur moyen serait de dénormaliser le champ de comptage sur le modèle de balise et de le mettre à jour chaque fois que l'article sera enregistré. Comment puis-je accomplir cela, ou peut-être y a-t-il un meilleur moyen?
La solution
Vous pouvez le faire en créant un modèle intermédiaire pour la relation M2M et l’utilisez comme crochet pour les signaux post_save
et post_delete
afin de mettre à jour la colonne dénormalisée dans le Article
table.
Par exemple, je le fais pour les questions
favorites dans soclone , où les utilisateurs
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 quelques discussions sur la liste de diffusion django-developers sur la mise en œuvre d'un moyen de déclaration déclarative des dénormalisations afin d'éviter d'avoir à écrire du code comme ci-dessus:
Autres conseils
Ceci est une nouvelle fonctionnalité de Django 1.2: http://docs.djangoproject.com/en/dev/ref / signaux / # m2m-modifié