Метод save_model

Метод save_model применяется в классе ModelAdmin и вызывается при сохранении объекта через административную панель. Он позволяет переопределить стандартное поведение сохранения, добавить дополнительную обработку данных, установить значения полей или выполнить действия до или после сохранения объекта в базе данных. Метод принимает несколько параметров: экземпляр запроса, экземпляр объекта, экземпляр формы и флаг изменения.

Синтаксис

pythonclass MyModelAdmin(admin.ModelAdmin):
  def save_model(self, request, obj, form, change):
    # Переопределение логики сохранения
    super().save_model(request, obj, form, change)

Пример . С добавлением текущего пользователя

Давайте создадим модель статьи и настроим административную панель так, чтобы при сохранении статьи автоматически заполнялось поле 'author' текущим пользователем:

pythonfrom django.db import models
from django.contrib.auth.models import User

class Article(models.Model):
  title = models.CharField(max_length=100)
  content = models.TextField()
  author = models.ForeignKey(User, on_delete=models.CASCADE)
  created_at = models.DateTimeField(auto_now_add=True)

  def __str__(self):
    return self.title
pythonfrom django.contrib import admin
from .models import Article

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
  list_display = ['title', 'author', 'created_at']
  
  def save_model(self, request, obj, form, change):
    if not obj.pk:  # Если объект новый
      obj.author = request.user
    super().save_model(request, obj, form, change)

Результат выполнения кода при создании новой статьи через админку:

python"Статья создана с автором: admin"

Пример . С модификацией данных

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

pythonfrom django.db import models

class Product(models.Model):
  name = models.CharField(max_length=100)
  price = models.DecimalField(max_digits=10, decimal_places=2)
  is_active = models.BooleanField(default=True)

  def __str__(self):
    return self.name
pythonfrom django.contrib import admin
from .models import Product

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
  list_display = ['name', 'price', 'is_active']
  
  def save_model(self, request, obj, form, change):
    obj.name = obj.name.upper()  # Преобразование имени в верхний регистр
    super().save_model(request, obj, form, change)

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

python"Товар 'laptop' сохранен как 'LAPTOP'"

Пример . С отправкой уведомления

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

pythonfrom django.db import models
from django.contrib.auth.models import User

class Order(models.Model):
  user = models.ForeignKey(User, on_delete=models.CASCADE)
  total = models.DecimalField(max_digits=10, decimal_places=2)
  status = models.CharField(max_length=20, default='new')
  created_at = models.DateTimeField(auto_now_add=True)

  def __str__(self):
    return f"Order {self.id} by {self.user}"
pythonfrom django.contrib import admin
from django.core.mail import send_mail
from .models import Order

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
  list_display = ['id', 'user', 'total', 'status', 'created_at']
  
  def save_model(self, request, obj, form, change):
    is_new = obj.pk is None
    super().save_model(request, obj, form, change)
    
    if is_new:
      send_mail(
        'New Order Created',
        f'Order #{obj.pk} has been created with total {obj.total}',
        'admin@example.com',
        ['admin@example.com'],
        fail_silently=True,
      )

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

python"Email notification sent for order #1"

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

  • метод delete_model,
    который переопределяет удаление объекта
  • метод get_queryset,
    который переопределяет выборку объектов
  • атрибут list_display,
    который управляет отображением полей в списке
  • атрибут list_filter,
    который добавляет фильтры в боковой панели