РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
166 of 818 menu

Сигнал pre_save

Сигнал pre_save отправляется непосредственно перед тем, как объект модели будет сохранен в базу данных. Он позволяет выполнить произвольный код на этапе подготовки объекта к сохранению, например, изменить значения полей, провести дополнительную валидацию или создать связанные объекты. Сигнал отправляется как при создании нового объекта, так и при обновлении существующего, и передает в обработчик сам экземпляр модели, флаг создания и дополнительные аргументы.

Синтаксис

from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=MyModel) def my_handler(sender, instance, raw, using, update_fields, **kwargs): # выполнить действия перед сохранением pass

Параметры обработчика

Обработчик сигнала pre_save получает следующие параметры:

  • sender - класс модели, отправившей сигнал
  • instance - экземпляр модели, который будет сохранен
  • raw - булевый флаг, указывающий, выполняется ли сохранение из фикстур
  • using - имя базы данных, используемой для сохранения
  • update_fields - список полей, переданных в метод save, или None, если не указаны

Пример

Рассмотрим модель Article, в которой перед сохранением нужно автоматически обновлять поле updated_at текущей датой:

from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver from django.utils import timezone class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @receiver(pre_save, sender=Article) def update_article_timestamp(sender, instance, **kwargs): instance.updated_at = timezone.now() # Создаем статью article = Article(title="First Article", content="Some content") article.save()

В этом примере перед сохранением каждой статьи в поле updated_at будет записано текущее время.

Пример

Перед сохранением пользователя автоматически преобразуем его email в нижний регистр:

from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver class User(models.Model): username = models.CharField(max_length=100) email = models.EmailField() is_active = models.BooleanField(default=True) @receiver(pre_save, sender=User) def normalize_user_email(sender, instance, **kwargs): if instance.email: instance.email = instance.email.lower() # Создаем пользователя user = User(username="john_doe", email="John@Example.com") user.save() # Проверяем результат print(f"Email: {user.email}")

Результат выполнения кода:

"Email: john@example.com"

Пример

Используем сигнал pre_save для автоматического создания связанного объекта при сохранении нового продукта:

from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver class Product(models.Model): name = models.CharField(max_length=100) price = models.IntegerField() class ProductLog(models.Model): product = models.OneToOneField(Product, on_delete=models.CASCADE) status = models.CharField(max_length=50) @receiver(pre_save, sender=Product) def create_product_log(sender, instance, **kwargs): if not instance.pk: # Новый продукт - создаем лог log = ProductLog(product=instance, status="created") log.save() # Создаем продукт product = Product(name="Laptop", price=1200) product.save() # Проверяем наличие лога has_log = ProductLog.objects.filter(product=product).exists() print(f"Log exists: {has_log}")

Результат выполнения кода:

"Log exists: True"

Пример

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

from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver class Category(models.Model): name = models.CharField(max_length=50) slug = models.SlugField(unique=True) is_active = models.BooleanField(default=True) @receiver(pre_save, sender=Category) def handle_category_save(sender, instance, **kwargs): if instance.pk is None: # Создание новой категории print(f"Creating new category: {instance.name}") else: # Обновление существующей категории print(f"Updating category: {instance.name}") # Создание новой категории category = Category(name="Technology", slug="tech") category.save() # Обновление категории category.is_active = False category.save()

Результат выполнения кода:

"Creating new category: Technology" "Updating category: Technology"

Смотрите также

  • сигнал post_save,
    который отправляется после сохранения объекта
  • сигнал pre_delete,
    который отправляется перед удалением объекта
  • метод save,
    который сохраняет объект в базу данных
  • метод clean,
    который выполняет валидацию полей модели
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить