← Назад к вопросам

Какие события могут быть в сигналах?

1.0 Junior🔥 171 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

События в сигналах (Django Signals)

Django signals — это механизм отправки и получения сообщений при определённых событиях в приложении. Используется dispatch pattern для декуплирования.

Встроенные сигналы Django

1. Сигналы моделей (django.db.models.signals)

pre_save — ДО сохранения модели в БД:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.contrib.auth.models import User

@receiver(pre_save, sender=User)
def normalize_email(sender, instance, **kwargs):
    """Привести email к нижнему регистру ДО сохранения"""
    instance.email = instance.email.lower()
    print(f"Pre-saving user: {instance.username}")

# Использование
user = User(username="john", email="JOHN@EXAMPLE.COM")
user.save()  # Сигнал срабатывает, email становится john@example.com

post_save — ПОСЛЕ сохранения модели:

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """Создать профиль при создании пользователя"""
    if created:  # Новый объект создан
        UserProfile.objects.create(user=instance)
        send_welcome_email(instance.email)
    else:  # Объект обновлён
        instance.profile.updated_at = timezone.now()
        instance.profile.save()
    
    print(f"Post-saved user: {instance.username}")

# Использование
user = User.objects.create(username="jane", email="jane@example.com")
# Сигнал post_save срабатывает, создаётся профиль

pre_delete — ДО удаления модели:

@receiver(pre_delete, sender=User)
def backup_user_data(sender, instance, **kwargs):
    """Сохранить данные пользователя ДО удаления"""
    UserBackup.objects.create(
        username=instance.username,
        email=instance.email,
        deleted_at=timezone.now()
    )
    print(f"Pre-deleting user: {instance.username}")

post_delete — ПОСЛЕ удаления модели:

@receiver(post_delete, sender=User)
def cleanup_after_user_deletion(sender, instance, **kwargs):
    """Очистить связанные данные ПОСЛЕ удаления"""
    # Удалить файлы
    if instance.profile.avatar:
        instance.profile.avatar.delete(save=False)
    
    # Отправить уведомление
    log_deletion(f"User {instance.username} deleted")
    
    print(f"Post-deleted user: {instance.username}")

# Использование
user = User.objects.get(id=123)
user.delete()  # post_delete сигнал срабатывает

2. Сигналы управления (django.core.management.signals)

call_command — перед выполнением управления команды:

from django.core.management.signals import pre_command, post_command

@receiver(pre_command)
def before_command(sender, **kwargs):
    print(f"Command starting: {sender}")

@receiver(post_command)
def after_command(sender, **kwargs):
    print(f"Command finished: {sender}")

# Использование
python manage.py migrate  # Сигналы срабатывают

3. Сигналы запросов (django.test.signals)

setting_changed — когда изменяется параметр конфигурации:

from django.test.signals import setting_changed

@receiver(setting_changed)
def on_setting_changed(sender, setting, **kwargs):
    if setting == "DEBUG":
        print(f"DEBUG mode changed")
    elif setting == "DATABASES":
        print("Database configuration changed")

4. Сигналы приложения (django.apps.signals)

apps_ready — когда приложение загружено:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = "myapp"
    
    def ready(self):
        """Вызывается когда приложение готово"""
        import myapp.signals  # Регистрируем сигналы
        print("MyApp is ready!")

5. Custom сигналы (пользовательские события)

Можно создавать свои сигналы:

from django.dispatch import Signal, receiver

# Определяем свой сигнал
order_completed = Signal()
payment_processed = Signal()
user_verified = Signal()

# Отправляем сигнал
class OrderService:
    def complete_order(self, order_id):
        order = Order.objects.get(id=order_id)
        order.status = "completed"
        order.save()
        
        # Отправляем свой сигнал
        order_completed.send(
            sender=self.__class__,
            order_id=order_id,
            user_id=order.user_id,
            total_amount=order.total
        )

# Слушаем сигнал
@receiver(order_completed)
def on_order_completed(sender, order_id, user_id, total_amount, **kwargs):
    print(f"Order {order_id} completed for user {user_id}: ${total_amount}")
    send_confirmation_email(user_id, order_id)
    update_analytics(user_id, total_amount)

6. Практический пример: Полный workflow

from django.db import models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.mail import send_mail

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    published = models.BooleanField(default=False)

class PostLike(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="likes")
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

# Сигналы
@receiver(post_save, sender=Post)
def post_published(sender, instance, created, **kwargs):
    """Уведомление при публикации поста"""
    if not created and instance.published:
        # Отправляем письма подписчикам
        followers = User.objects.filter(following=instance.author)
        for follower in followers:
            send_mail(
                subject=f"New post: {instance.title}",
                message=f"Check out: {instance.content[:100]}...",
                from_email="noreply@example.com",
                recipient_list=[follower.email],
            )

@receiver(post_save, sender=PostLike)
def on_post_liked(sender, instance, created, **kwargs):
    """Уведомление автору при like"""
    if created:
        post = instance.post
        likes_count = post.likes.count()
        
        # Отправляем уведомление каждый 10-й like
        if likes_count % 10 == 0:
            send_mail(
                subject=f"Your post reached {likes_count} likes!",
                message=f"{post.title} is getting popular!",
                from_email="noreply@example.com",
                recipient_list=[post.author.email],
            )

@receiver(post_delete, sender=PostLike)
def on_post_unliked(sender, instance, **kwargs):
    """Логирование unlike"""
    post = instance.post
    likes_count = post.likes.count()
    print(f"Post {post.id} now has {likes_count} likes")

7. Подключение сигналов

В 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  # Регистрируем сигналы

В signals.py:

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import User, UserProfile

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

8. Сравнение подходов

ПодходКогда использоватьПлюсыМинусы
SignalsПобочные эффектыДекуплированиеСложна отладка
OverridesРасширение моделиЯвноТесная связь
ManagersКастомные запросыПереиспользованиеНе для побочных эффектов
MiddlewareГлобальные эффектыЛовит всеСложна для моделей

События в сигналах: Полный список

Модели:

  • pre_save — перед сохранением
  • post_save — после сохранения
  • pre_delete — перед удалением
  • post_delete — после удаления

Custom сигналы:

  • Любые события которые определишь

Система:

  • setting_changed — изменение конфигурации
  • pre_command / post_command — управление командами
  • apps_ready — готовность приложения

Signals — мощный инструмент для декуплирования логики, но используй их осторожно: они делают код менее явным и сложнее отлаживаемым.