Александр Кошелев
Александр Кошелев Python-разработчик

Revisited: M2M отношение и post_save сигнал

Давным давно описывал решение проблемы с сигналами и ManyToMany полями. Вопрос остался актуальным и по сей день и частенько всплывает в форумах.

Напомню суть: в save методе (или в обработчике pre_/post_save сигналов) модели родителе (Post) нельзя узнать об изменениях в отношениях с чайлдами (Comment). Это связано с тем, что чайлды присоединяются к родителю после его сохранения.

С тех пор много воды утекло и в джанге появилась возможность решить данную задачу иначе. И мне кажется даже более правильно, нежели выдумывать новое поле.

В версии 1.0 нам дали возможность задать для M2M связывания свою модель. Применительно к моему старому примеру это будет выглядеть так:

class Comment(models.Model):
    #...

class Post(models.Model):
    comments = models.ManyToManyField(Comment, through='PostToCommentRelation')
    #...
    
class PostToCommentRelation(models.Model):
    post = models.ForeignKey(Post)
    comment = models.ForeignKey(Comment)

И вот как только мы сделали эту модель и явно указали её в качестве промежуточной, у нас появилась возможность абсолютно стандартным путем отслеживать изменения связей. Поскольку это обычная модель, то она сама имеет этот самый пресловутый post_save сигнал, повесив обработчик на который, вы всегда сможете отследить какие два объекта были связаны и как-то на это прореагировать.

def relation_change_handler(sender, instance, created, **kwargs):
    # работа с instance.post или instance.comment
    pass

signals.post_save.connect(relation_change_handler, sender=PostToCommentRelation)

Теперь такой подход мне кажется более рациональным и религиозно правильным:-)

P.S.: Очередное обновление в блоге - каптчи больше нет. Подружил движок с Akismet и теперь как все белые люди защищен им. Так что если вы не пользуетесь OpenID (кому легко уже сейчас), то комментировать стало ещё проще! Welcome!:-)

comments powered by Disqus