Что такое сигнал post_save в Django и когда его следует использовать

Ответ

post_save — это сигнал в фреймворке Django, который отправляется сразу после того, как метод save() модели успешно завершил свою работу и данные были сохранены в базу данных. Это часть встроенной системы сигналов, позволяющей выполнять определенные действия в ответ на события, происходящие в приложении.

Использование сигналов, таких как post_save, позволяет отделить логику, не связанную напрямую с сохранением модели, и реализовать принцип слабой связанности (low coupling) компонентов системы.

Принцип работы:

Вы создаете функцию-обработчик (receiver), которая будет вызываться каждый раз, когда сигнал post_save срабатывает для указанной модели (sender).

Основной пример:

Предположим, мы хотим автоматически создавать профиль пользователя (UserProfile) каждый раз, когда создается новый пользователь (User).

# myapp/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import UserProfile

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """Обработчик сигнала для создания профиля."""
    if created:
        # Аргумент 'created' равен True только при первом сохранении
        UserProfile.objects.create(user=instance)

# myapp/apps.py
from django.apps import AppConfig

class MyappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

    def ready(self):
        import myapp.signals # Важно импортировать сигналы здесь

Ключевые аргументы обработчика:

  • sender: Класс модели, который отправил сигнал (в примере — User).
  • instance: Конкретный экземпляр модели, который был сохранен.
  • created: Булево значение. True, если в базе данных была создана новая запись (эквивалентно INSERT). False, если запись была обновлена (UPDATE).

Частые сценарии использования:

  • Создание связанных объектов (как в примере выше).
  • Денормализация данных или обновление агрегированных значений.
  • Инвалидация кэша при изменении данных.
  • Отправка уведомлений (например, по email) после создания или обновления объекта.

Ответ 18+ 🔞

Ну, слушай, смотри, вот есть у тебя в Джанго эта штука — post_save. Это как такой сигнальчик, понимаешь? Ты модель сохранил в базу, всё, save() отработал, и тут — бац! — в эфир летит этот самый сигнал. А ты где-то в другом углу приложения можешь его поймать и сделать какую-нибудь свою, ебать, магию. Красота же, да? Разделил логику, не городи всё в один метод, принципы всякие соблюдаешь.

Как это, блядь, работает:

Представь, ты — диджей на радиостанции. Ты (post_save) объявляешь в эфир: "Так, народ, только что сохранился объект модели User!". А где-то в другом конце города у тебя сидит радиолюбитель с приёмничком. Это твой обработчик, receiver. Он эту хуйню ловит и начинает что-то своё делать.

Вот тебе классика жанра, на пальцах:

Допустим, у тебя есть юзер, и на каждого юзера надо автоматом создать профиль. Без этого сигнала пришлось бы везде, где создаёшь юзера, руками ещё и профиль лепить. Заебешься, блядь. А так — один раз написал и забыл.

# myapp/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import UserProfile

@receiver(post_save, sender=User) # Вешаем наш приёмничек на волну 'post_save' от модели User
def create_user_profile(sender, instance, created, **kwargs):
    """Функция, которая сработает, когда юзера сохранят."""
    if created:  # Вот это ключевой момент, ёпта! True — значит юзера только что СОЗДАЛИ, а не обновили.
        UserProfile.objects.create(user=instance) # Бдыщ! Профиль готов.

# myapp/apps.py
from django.apps import AppConfig

class MyappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

    def ready(self):
        import myapp.signals  # СУКА, ВАЖНО! Сигналы надо импортировать тут, иначе они не загрузятся!

Аргументы, которые тебе кидают в обработчик (приёмник):

  • sender: Это кто кричал в эфир. Класс модели, в нашем случае — User.
  • instance: А это сам конкретный чувак, которого только что сохранили. Объект модели, живой, с его полями и данными.
  • created: Флаг, просто пиздец какой важный. True — запись новая, только что в базу вставили. False — значит старую запись просто обновили. Без него можно наобновлять столько хуйни...

Где это, блядь, пригождается, кроме профилей?

Да везде, где надо что-то сделать ПОСЛЕ сохранения, но не в лоб, в том же методе.

  • Создать кучу связанных объектов разом.
  • Посчитать какие-то суммарные поля в другой модели (денормализация, ёпта).
  • Сбросить кэш, потому что данные изменились, а кэш ещё старый.
  • Отправить письмо или уведомление, что, мол, "ваш заказ №666 создан, идите нахуй".