Ответ
Для отслеживания изменений в ManyToManyField используется специальный сигнал m2m_changed. Стандартные сигналы, такие как post_save, не срабатывают для M2M-отношений, поскольку они управляются через отдельную промежуточную таблицу, а не прямым изменением поля в основной модели.
Сигнал m2m_changed отправляется до и после добавления, удаления или очистки связей.
Пример:
Предположим, у нас есть модели Post и Tag со связью ManyToManyField.
# models.py
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=50)
class Post(models.Model):
title = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag, related_name='posts')
Чтобы отследить добавление тега к посту, нужно подключиться к сигналу m2m_changed, указав в sender промежуточную модель (Post.tags.through).
# signals.py
from django.db.models.signals import m2m_changed
from django.dispatch import receiver
from .models import Post
@receiver(m2m_changed, sender=Post.tags.through)
def tags_changed_handler(sender, instance, action, pk_set, **kwargs):
"""
Обработчик сигнала изменения M2M-связи для тегов поста.
"""
print(f"Действие: {action} для поста '{instance.title}'")
if action == "post_add":
# Действие после добавления связей
added_tags = instance.tags.filter(pk__in=pk_set)
print(f"Добавлены теги: {[tag.name for tag in added_tags]}")
elif action == "post_remove":
# Действие после удаления связей
print(f"Удалены связи с тегами (ID): {pk_set}")
elif action == "post_clear":
# Действие после полной очистки связей
print("Все теги были удалены.")
Ключевые аргументы обработчика:
sender: Промежуточная модель, управляющая связью (Post.tags.through).instance: Экземпляр модели, у которой было изменено M2M-поле (в нашем случае — экземплярPost).action: Строка, описывающая тип действия. Основные значения:'pre_add','post_add''pre_remove','post_remove''pre_clear','post_clear'
pk_set: Набор (set) первичных ключей объектов, которые были добавлены или удалены.