← К оглавлению урока

🐛 Типичные ошибки: Inline и Admin Actions

⚡ Топ-3 ошибки

  1. ForeignKey не на родительскую модель — Django выбросит ImproperlyConfigured
  2. queryset.update() не триггерит сигналы — если нужны post_save — итерировать вручную
  3. Забыть зарегистрировать обе модели — Inline не появится в Admin

Ошибки при настройке Inline

Ошибка 1: Нет ForeignKey на родительскую модель

Симптом: ImproperlyConfigured: BookInline has no ForeignKey to Publisher

Причина: В Inline-классе указана модель, у которой нет ForeignKey на модель, к которой подключён Inline.

# Плохо: у Book нет ForeignKey на Publisher
class Book(models.Model):
    title = models.CharField(max_length=200)
    # нет поля publisher!

class BookInline(admin.TabularInline):
    model = Book  # ошибка — нет FK на Publisher
# Хорошо: добавляем ForeignKey
class Book(models.Model):
    title = models.CharField(max_length=200)
    publisher = models.ForeignKey(
        Publisher, on_delete=models.CASCADE
    )  # FK на Publisher есть

Ошибка 2: Забыть выполнить миграции после изменения модели

Симптом: OperationalError: no such column: books_book.publisher_id

Причина: Добавили поле в модель, но не применили миграцию.

# Плохо: добавили поле, не мигрировали
class Book(models.Model):
    publisher = models.ForeignKey(Publisher, ...)  # добавили
# забыли: python manage.py makemigrations && migrate
# Правильный порядок:
# 1. Изменить models.py
# 2. python manage.py makemigrations
# 3. python manage.py migrate
# 4. Перезапустить runserver

Ошибка 3: Не зарегистрировать связанную модель

Симптом: Inline отображается, но нет раздела Books в Admin-меню.

Причина: Зарегистрировали только Publisher, забыли Book.

# Плохо: только Publisher
admin.site.register(Publisher, PublisherAdmin)
# admin.site.register(Book) — забыли!
# Хорошо: обе модели
admin.site.register(Publisher, PublisherAdmin)
admin.site.register(Book)

Примечание: Inline всё равно работает без регистрации Book, но тогда книги нельзя редактировать отдельно от издательства.

Ошибка 4: Неправильный порядок inlines

Симптом: Inline не отображается на странице.

Причина: inlines написано с маленькой буквы, или список не является списком.

# Плохо
class PublisherAdmin(admin.ModelAdmin):
    inline = [BookInline]    # опечатка: inline вместо inlines
    inlines = BookInline     # не список!
# Хорошо
class PublisherAdmin(admin.ModelAdmin):
    inlines = [BookInline]   # список (даже из одного элемента)

Ошибка 5: extra=0 без min_num — нельзя добавить новый объект

Симптом: Пустых форм нет, кнопки «Добавить» нет.

Причина: extra=0 убирает пустые строки, но кнопка «Add another» всё равно должна быть.

# extra=0 — норма, если объекты уже есть
class BookInline(admin.TabularInline):
    model = Book
    extra = 0  # не показывать пустые строки,
               # но кнопка "Add another Book" остаётся

Ошибки при работе с Admin Actions

Ошибка 6: queryset.update() не вызывает сигналы

Симптом: Массовое обновление через action работает, но связанная логика (отправка email, обновление кеша) не выполняется.

Причина: queryset.update() — прямой SQL UPDATE, он не вызывает метод save() и не отправляет сигналы post_save/pre_save.

# Плохо: если нужны сигналы
def mark_done(self, request, queryset):
    queryset.update(status='done')  # сигналы НЕ срабатывают
# Хорошо: если нужны сигналы — вручную итерировать
def mark_done(self, request, queryset):
    for obj in queryset:
        obj.status = 'done'
        obj.save()  # вызывает save() и сигналы, но медленнее
Выбор зависит от задачи: для скорости — queryset.update(), для сигналов — цикл с save().

Ошибка 7: Действие не появляется в списке

Симптом: Кастомный action не виден в выпадающем списке Admin.

Причина: Забыли добавить в actions, или написали имя строкой вместо ссылки на функцию.

# Плохо
class BookAdmin(admin.ModelAdmin):
    def update_created_at(self, request, queryset):
        queryset.update(created_at=timezone.now())
    # actions не объявлен!

# Тоже плохо
class BookAdmin(admin.ModelAdmin):
    actions = ["update_created_at"]  # строка, а не функция
# Хорошо
class BookAdmin(admin.ModelAdmin):
    def update_created_at(self, request, queryset):
        queryset.update(created_at=timezone.now())
    update_created_at.short_description = "Update created_at"
    actions = [update_created_at]  # ссылка на функцию

Ошибка 8: Неправильная сигнатура action-функции

Симптом: TypeError: update_created_at() missing 1 required positional argument

Причина: Функция action должна принимать ровно 3 параметра.

# Плохо: не хватает параметров
def update_created_at(queryset):
    queryset.update(created_at=timezone.now())
# Хорошо: все три параметра обязательны
def update_created_at(self, request, queryset):
    queryset.update(created_at=timezone.now())