🐛 Типичные ошибки: Inline и Admin Actions
⚡ Топ-3 ошибки
- ForeignKey не на родительскую модель — Django выбросит ImproperlyConfigured
- queryset.update() не триггерит сигналы — если нужны post_save — итерировать вручную
- Забыть зарегистрировать обе модели — 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())