Поиск…


параметры

Класс / Метод Почему?
Класс UserProfile () Класс UserProfile расширяет модель пользователя Django по умолчанию .
Метод create_profile () Метод create_profile () выполняется, когда post_save пользовательской моделью post_save .

замечания

Теперь детали.

Сигналы Django - это способ информировать ваше приложение о некоторых задачах (например, о модели до или после сохранения или удаления), когда это происходит.

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

Например, в любое время , когда создается новый пользователь Django, Пользовательская модель выпускает сигнал с ассоциированными параметрами, такими как sender=User что позволяет вам конкретно настроить ваше прослушивание сигналов на конкретную деятельность, которая происходит, в этом случае новое создание пользователя ,

В приведенном выше примере намерение состоит в создании объекта UserProfile сразу после создания объекта User. Поэтому, прослушивая сигнал post_save из модели User (по умолчанию Django User Model), мы создаем объект UserProfile сразу после создания нового User .

Документация Django предоставляет обширную документацию по всем возможным сигналам .

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

"С большой властью приходит большая ответственность". Может возникнуть соблазн иметь сигналы, разбросанные по всему вашему приложению или проекту, только потому, что они потрясающие. Ну, не надо. Потому что они классные, не делают их идеальным решением для каждой простой ситуации, которая приходит на ум.

Сигналы отлично подходят, как обычно, не для всех. Вход / Выход, сигналы отличные. Ключевые модели, выпускающие знаки, такие как User Model, если они прекрасны.

Создание сигналов для каждой модели в вашем приложении может быть подавляющим в какой-то момент и победить всю идею спаррингового использования сигналов Django.

Не используйте сигналы, когда (на основе Two Scoops of Django book ):

  • Сигнал относится к одной конкретной модели и может быть перенесен в один из методов этой модели, возможно, вызванный функцией save() .
  • Сигнал можно заменить специальным методом диспетчера модели.
  • Сигнал относится к определенному виду и может быть перемещен в эту точку зрения

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

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

Расширение примера профиля пользователя

Этот пример представляет собой фрагмент, взятый из расширенного профиля пользователя Django, такого как Pro

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
 
class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='user')
    website = models.URLField(default='', blank=True)
    bio = models.TextField(default='', blank=True)

def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        user_profile = UserProfile(user=user)
        user_profile.save()
post_save.connect(create_profile, sender=User)

Разный синтаксис для отправки / предварительного сигнала

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
 
class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='user')
    website = models.URLField(default='', blank=True)
    bio = models.TextField(default='', blank=True)

@receiver(post_save, sender=UserProfile)
def post_save_user(sender, **kwargs):
    user = kwargs.get('instance')
    if kwargs.get('created'):
        ...

Как найти, является ли это вставкой или обновлением в сигнале pre_save

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

Для этого вы можете проверить состояние объекта модели:

    @receiver(pre_save, sender=User)
    def pre_save_user(sender, instance, **kwargs): 
        if not instance._state.adding:
            print ('this is an update')
        else:
            print ('this is an insert')

Теперь каждый раз, когда выполняется действие save , будет pre_save сигнал pre_save и будет печатать:

  • this is an update если действие происходит от действия обновления.
  • this is an insert если действие происходит от действия вставки.

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

Наследование сигналов на расширенных моделях

Сигналы Django ограничиваются точными сигнатурами класса при регистрации, и поэтому подклассы моделей не сразу регистрируются на один и тот же сигнал.

Возьмите эту модель и, например, сигнал

class Event(models.Model):
    user = models.ForeignKey(User)


class StatusChange(Event):
    ...


class Comment(Event):
    ...


def send_activity_notification(sender, instance: Event, raw: bool, **kwargs):
    """
    Fire a notification upon saving an event
    """

    if not raw:
        msg_factory = MessageFactory(instance.id)
        msg_factory.on_activity(str(instance))
post_save.connect(send_activity_notification, Event)

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

post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)

С Python 3.6 вы можете использовать некоторые дополнительные методы класса, встроенные в классы, чтобы автоматизировать эту привязку.

class Event(models.Model):

    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        post_save.connect(send_activity_notification, cls)


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow