Сигнал post_init
Сигнал post_init относится к встроенным сигналам Django
и находится в модуле django.db.models.signals.
Он отправляется после того, как экземпляр модели был создан
и все его поля были инициализированы значениями. Этот сигнал
полезен для выполнения дополнительной настройки объекта,
которая должна происходить сразу после его создания,
независимо от того, загружен ли объект из базы данных
или создан в коде. Сигнал post_init не передаёт
никаких дополнительных аргументов, кроме самого экземпляра
модели и имени отправителя.
Синтаксис
from django.db.models.signals import post_init
from django.dispatch import receiver
@receiver(post_init, sender=MyModel)
def my_handler(sender, instance, **kwargs):
# Действия после инициализации
pass
Параметры обработчика
Функция-обработчик сигнала post_init принимает
следующие параметры:
-
sender- класс модели, отправившей сигнал. -
instance- экземпляр модели, который был только что инициализирован. -
**kwargs- дополнительные именованные аргументы, передаваемые сигналом.
Пример . С обработкой после загрузки из базы
Рассмотрим модель Article, у которой есть поле
word_count. После инициализации объекта
мы хотим автоматически подсчитывать количество слов
в тексте статьи:
from django.db import models
from django.db.models.signals import post_init
from django.dispatch import receiver
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
word_count = models.IntegerField(default=0)
def __str__(self):
return self.title
@receiver(post_init, sender=Article)
def article_post_init(sender, instance, **kwargs):
if instance.content:
words = instance.content.split()
instance.word_count = len(words)
print(f"Article '{instance.title}' has {instance.word_count} words")
Теперь при создании нового экземпляра Article
сразу после инициализации будет выполняться подсчёт слов:
from myapp.models import Article
article = Article(
title="My First Article",
content="This is the content of the first article."
)
print(article.word_count)
Результат выполнения кода:
"Article 'My First Article' has 8 words"
"8"
Пример . С модификацией атрибутов
Сигнал post_init можно использовать для добавления
динамических атрибутов экземпляру. Например, добавим
атрибут full_name для модели User:
from django.db import models
from django.db.models.signals import post_init
from django.dispatch import receiver
class User(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self):
return f"{self.first_name} {self.last_name}"
@receiver(post_init, sender=User)
def user_post_init(sender, instance, **kwargs):
instance.full_name = f"{instance.first_name} {instance.last_name}"
После инициализации каждый экземпляр будет содержать
дополнительный атрибут full_name:
from myapp.models import User
user = User(first_name="John", last_name="Doe", email="john@example.com")
print(user.full_name)
Результат выполнения кода:
"John Doe"
Пример . С кешированием вычисляемых данных
Сигнал post_init полезен для предварительного
вычисления и кеширования данных, которые часто используются
в бизнес-логике. Рассмотрим модель Product
с вычисляемым рейтингом:
from django.db import models
from django.db.models.signals import post_init
from django.dispatch import receiver
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField(default=0.0)
review_count = models.IntegerField(default=0)
def __str__(self):
return self.name
@receiver(post_init, sender=Product)
def product_post_init(sender, instance, **kwargs):
if instance.review_count > 0:
instance.cached_rating = instance.rating
else:
instance.cached_rating = None
instance.discount_price = instance.price * 0.9
Теперь при обращении к экземпляру Product
доступны кешированные значения:
from myapp.models import Product
product = Product(
name="Laptop",
price=1000.00,
rating=4.5,
review_count=10
)
print(product.cached_rating)
print(product.discount_price)
Результат выполнения кода:
"4.5"
"900.00"
Важные особенности
Сигнал post_init имеет несколько важных
особенностей, которые следует учитывать:
-
Сигнал отправляется только один раз при инициализации
экземпляра, даже если объект был загружен из базы данных
через
QuerySet. -
В отличие от
pre_init, сигналpost_initвызывается уже после того, как все поля объекта получили свои значения. - Сигнал не передаёт словарь аргументов, поэтому изменения, внесённые в обработчике, не влияют на процесс инициализации.
-
Обработчики
post_initвыполняются синхронно и в том порядке, в котором они были зарегистрированы.
Смотрите также
-
сигнал
pre_init,
который отправляется до инициализации экземпляра -
сигнал
pre_save,
который отправляется перед сохранением объекта -
сигнал
post_save,
который отправляется после сохранения объекта -
метод
refresh_from_db,
который обновляет объект из базы данных