Django 5 для начинающих

Прогресс по курсу:  9/1004

7.4 Профили пользователей и пользовательские поля модели User
5 из 8 шагов пройдено
0 из 15 баллов  получено

Сигналы в Джанго

Обратите внимание, что на данный момент нам нужно переходить на страницу администратора, чтобы создать профиль всякий раз, когда создается пользователь. Было бы здорово, если бы мы могли автоматически создавать профили при создании нового пользователя. Для этого мы используем сигналы.

Но что такое сигналы??

Сигналы используются для выполнения некоторых действий по модификации/созданию определенной записи в базе данных.

В сигнале у нас есть следующие основные понятия:

  • Отправитель: обычно это модель, которая уведомляет получателя о возникновении события.

  • Приёмник: обычно получатель - это функция, которая работает с данными после того, как она уведомлена о каком-либо действии, которое произошло, например, когда экземпляр пользователя только что был сохранен в базе данных.

  • Связь между отправителями и получателями осуществляется через «диспетчеров сигналов».

Пример использования: с помощью сигналов мы можем создать экземпляр профиля сразу после создания нового экземпляра пользователя в базе данных. Django рекомендует размещать сигналы в каталоге приложения как отдельный модуль.

Поэтому создайте файл signals.py внутри приложения accounts и добавьте следующий код:

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

from .models import Profile


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

create_profile это функция приемника, которая запускается каждый раз при создании пользователя. Пользователь является отправителем, который несет ответственность за отправку уведомления.

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

Следующим шагом является подключение приемников методом ready() конфигурации приложения путем импорта модуля сигналов.

Откройте apps.py, где мы можем включить любую конфигурацию приложения для пользовательского приложения. Добавим новую функцию в наш класс:

from django.apps import AppConfig


class AccountsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'accounts'

    def ready(self):
        import accounts.signals

Что мы сделали, так это переопределили ready() метод конфигурации пользовательского приложения для выполнения задачи инициализации, которая регистрирует сигналы.

Теперь, когда у нас есть все вышеперечисленное, в следующем шаге мы создадим форму, в которой пользователи будут обновлять свой профиль и отображать информацию внутри шаблона.


  • Комментария
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

Очень интересная тема, спасибо!

Не понимаю, для чего нужен сигнал save_profile , мы же уже создали объект Profile в create_profile?

@Кирилл_Семенихин, Спасибо, вы правы, убрали лишнюю функцию в сигналах.

Не понимаю, почему инициализацию сигналов нужно делать явно по ready?

@Антон_Глухенко, Потому что этот метод(AppConfig.ready()) вызывается после загрузки всех приложений и моделей. Можете почитать в документации.

@Илья_Перминов, кажется я осознал в чем дело.

Поскольку в сигналах мы явно используем модели User/Profile (работать с которыми мы можем только после загрузки приложения), то и работать с сигналами мы можем только после полной инициализации приложения, т.е. через метод ready.

Если вынести импорт сигналов до класса AccountsConfig то будет возникать ошибка вида (из-за обращения к моделям, не проинициализированным)

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

PS: интересно, бывают ли сценарии при которых в сигналах приложения A используются модели из приложения B (которое грузится соответственно позже A)

@Антон_Глухенко, я думаю что бывают, но считаю это не самой удачной практикой. Даже в данном случае, эта User/Profile модель не самая удачная, в том плане, что редко ее в проектах можно встретить и она не удобна. Проще сделать на AbstractUser модели, добавив нужные поля. И все будет храниться в одной модели. В этом курсе мы не рассматриваем кастомные юзер модели, а во втором курсе мы делаем проекты уже на них.