12 способов кастомизации Django admin — поиск, фильтры, инлайны, действия, автодополнение, list_editable и оптимизация запросов — которые значительно повышают продуктивность.

Я обожаю функции-бумеранги: сделал работу один раз — и они продолжают приносить тебе пользу. Административная панель Django просто набита ими. Небольшие, точечные настройки, которые сбривают минуты с каждой задачи, пока ты не замечаешь, что к пятнице появилось свободное место. Вот 12 изменений, которые стабильно будут помогать вам экономить время, каждую неделю.

Базовая модель
В качестве примера представьте:

# shop/models.py
class Brand(models.Model):
    name = models.CharField(max_length=120)

class Product(models.Model):
    brand = models.ForeignKey(Brand, on_delete=models.PROTECT)
    name = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

1) Действительно работающий поиск.
Сделай поле с поиском с помощью search_fields действительно рабочим. Так же с читабельным заголовком.

# shop/admin.py
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    search_fields = ["name", "brand__name"]  # Поиск
    search_help_text = "Search by product or brand" # Заголовок

Почему это экономит время? Больше не нужно искать вручную объект. Вбиваете название поля и ищите его.

2) Показать важное в списке — list_display с сортируемыми методами
Выводите поля, о которых вас часто спрашивают — цена, активность, бренд — и сохраняйте возможность их сортировки.

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ("name", "brand_name", "price", "is_active", "created_at")
    ordering = ("-created_at",)

    def brand_name(self, obj):
        return obj.brand.name
    brand_name.admin_order_field = "brand__name"  # включаем сортировку
    brand_name.short_description = "Brand"

Почему это экономит время? Ноль кликов! Больше не нужно переходить на страницу объекта, дабы узнать очевидную информацию о нем.

3) Фильтры, которыми вы будете пользоваться на самом деле (включая кастомные)
Быстро отбирайте по бренду и актуальности; добавьте собственный фильтр «Активно/Неактивно», который отражает бизнес-логику.

from django.contrib.admin import SimpleListFilter

class ActiveFilter(SimpleListFilter):
    title = "status"
    parameter_name = "status"

    def lookups(self, request, model_admin):
        return [("active", "Active"), ("inactive", "Inactive")]

    def queryset(self, request, qs):
        if self.value() == "active":
            return qs.filter(is_active=True)
        if self.value() == "inactive":
            return qs.filter(is_active=False)
        return qs

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_filter = ("brand", "created_at", ActiveFilter)  
    date_hierarchy = "created_at"

Почему это экономит время? Фильтрация по активным, неактивным. Больше никто не тратит время на поиск активных или неактивных объектов.

4) Автодополнение вместо выпадающих списков на 5000 строк
Предотвращайте зависание страницы, вызванное огромными выпадающими списками для внешних ключей.

# shop/admin.py
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    autocomplete_fields = ["brand"]  # Поле "бренд" теперь с автодополнением

@admin.register(Brand)
class BrandAdmin(admin.ModelAdmin):
    search_fields = ["name"]  # обязательно для работы автодополнения

Почему это экономит время? Печатать удобнее, чем выбирать. Можно выбрать случайно не тот. Так же спасает от зависания, когда этих полей может быть тысячи.

5) Устраните N+1 проблему в списках изменений (changelists)
Страницы со списками объектов печально известны лавиной лишних запросов. Две строчки кода решают большую часть проблем.

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_select_related = ("brand",)

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        return qs.select_related("brand")  # Наш спаситель

Почему это экономит время? Страницы загружаются быстро, благодаря select_related. Сотрудникам больше не приходится ждать, пока появятся новые данные.

6) Массовое редактирование прямо в списке — list_editable
Изменяйте булевы флаги или корректируйте цены, не открывая страницы отдельных объектов.

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ("name", "brand_name", "price", "is_active")
    list_editable = ("price", "is_active")
    list_display_links = ("name",)  

Почему это экономит время? Небольшие изменения в 20 элементах занимают секунды, а не 20 загрузок страниц. Меньшая нагрузка на сервер, дьявол кроется в мелочах.

7) Действия в админке, которые соответствуют реальным рабочим процессам
Два основных примера: «Опубликовать/Снять с публикации» и «Экспорт в CSV». Создавайте идемпотентные и информативные действия.

import csv
from django.http import HttpResponse

@admin.action(description="Пометить выбранные как активные")
def mark_active(modeladmin, request, queryset):
    updated = queryset.update(is_active=True)
    modeladmin.message_user(request, f"Активировано {updated} товаров.")

@admin.action(description="Экспорт выбранных в CSV")
def export_csv(modeladmin, request, queryset):
    resp = HttpResponse(content_type="text/csv")
    resp["Content-Disposition"] = "attachment; filename=products.csv"
    writer = csv.writer(resp)
    writer.writerow(["id", "name", "brand", "price", "is_active"])
    for p in queryset.select_related("brand"):
        writer.writerow([p.id, p.name, p.brand.name, p.price, p.is_active])
    return resp

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    actions = [mark_active, export_csv]
    actions_on_top = True
    actions_on_bottom = False

Почему это экономит время? Все делается в один клик

8) Редактирование связанных данных прямо в форме
Работайте с дочерними элементами, не покидая страницу.

class Image(models.Model):
    product = models.ForeignKey(
      Product, on_delete=models.CASCADE, 
      related_name="images")
    
    url = models.URLField()
    is_primary = models.BooleanField(default=False)
class ImageInline(admin.TabularInline):
    model = Image
    extra = 0
    fields = ("url", "is_primary")
    classes = ("collapse",)

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = [ImageInline]

Почему это экономит время? На одном экране отображается весь блок работы.

8) Редактирование связанных данных прямо в форме
Работайте с дочерними элементами, не покидая страницу.

from django.db import models
from django.forms import TextInput, NumberInput

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {"widget": TextInput(attrs={"size": 60})},
        models.DecimalField: {"widget": NumberInput(attrs={"step": "0.01"})},
    }

Почему это экономит время? Меньше ошибочных нажатий и правок. Форма "кажется правильной" для данных.

9) Улучшенные виджеты и значения по умолчанию через formfield_overrides
Понятные формы способствуют внесению точных данных.

from django.db import models
from django.forms import TextInput, NumberInput

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {"widget": TextInput(attrs={"size": 60})},
        models.DecimalField: {"widget": NumberInput(attrs={"step": "0.01"})},
    }

Почему это экономит время? Меньше ошибочных нажатий и правок. Форма "кажется правильной" для данных.

10) Группировка полей: fieldsetsreadonly_fields и скрываемые секции
Упрощайте интерфейс для сотрудников, сохраняя доступ к чувствительным данным только для просмотра.

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    readonly_fields = ("created_at",)
    fieldsets = (
        ("Basics", {"fields": ("name", "brand", "price", "is_active")}),
        ("System", {"fields": ("created_at",), "classes": ("collapse",)}),
    )

Почему это экономит время? Редакторы сосредотачиваются на том, что они могут изменить. Системные поля доступны только тогда, когда они нужны, и не мешают в остальное время.

11) Пагинация и сохранение с учетом контекста
Сохраняйте место при переходе по страницам и выходе из них.

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_per_page = 50
    preserve_filters = True
    save_on_top = True

Почему это экономит время? Вы не теряете свои фильтры после сохранения объекта и не прокручиваете страницу слишком часто.

12) Создайте фирменный стиль администратора, чтобы люди чувствовали себя ":как дома".
Небольшие возможности имеют значение.

from django.contrib import admin
admin.site.site_header = "Shop Admin"
admin.site.site_title = "Shop Admin"
admin.site.index_title = "Operations Console"

Почему это экономит время? Новые члены команды быстрее ориентируются в админке. Меньше вопросов по типу "где я?".

Небольшая инструкция по созданию быстрого списка объектов (Changelist)

  • Отображение: показывайте то, что нужно сотрудникам (list_display), и обеспечивайте сортировку.

  • Поиск: используйте search_fields + стандартные фильтры (+ кастомные SimpleListFilter).

  • Скорость: select_related/prefetch_related, ограничение столбцов, list_per_page.

  • Действия: list_editable для мелких правок, actions — для масштабных операций.

  • Сохранение контекста: preserve_filters чтобы сотрудники возвращались к тому же срезу данных.

Мини-кейс: Сокращение времени работы с каталогом с 40 минут до 8

Раньше у нас была еженедельная рутина: обновить цены для товаров со статусом "неактивен, но скоро пополним", опубликовать 20 товаров, выгрузить отчёт для отдела закупок. 

После внедрения улучшений:

  • Кастомный фильтр по статусу и поиск по бренду мгновенно сужали список до нужной группы товаров.

  • list_editable позволял переключить 20 флагов is_active одним действием.

  • Кастомное действие «Экспорт в CSV» заменило ручное создание таблицы.

  • select_related("brand") обеспечил мгрененную загрузку страницы с 1500 товарами.

Теперь задача выполняется одним человеком за восемь минут. Остальные перестали избегать админки.

Заметки о тестировании и безопасности

  • Действия должны быть идемпотентными и сообщать, сколько строк было изменено.

  • Предпочитайте массовые обновления (queryset.update)
    циклам в действиях.

  • Выносите тяжелые операции в фоновые задачи — действия могут ставить задачу в очередь и возвращать пользователю сообщение о статусе.

  • Для диагностики производительности используйте Django Debug Toolbar: ищите лишние запросы, вызванные методами в list_display или встроенными формами (inlines).

Итог

Админка Django - это не побочный проект, а место, где происходит большая часть вашей бизнес-логики. Когда вы настраиваете поиск, фильтры и массовые операции - и устраняете медленные запросы - вы создаёте кумулятивный эффект. Десять минут сэкономлено сегодня, десять завтра - и через неделю это уже сэкономленный час.

Комментарии (7)


  1. Ver_P
    08.10.2025 22:44

    Значится думаешь завезли новую кастомную админку для джанго, а оказалось про базовые настройки админки рассказывают..


  1. sashis
    08.10.2025 22:44

    Предпочитайте массовые обновления (queryset.update) циклам в действиях.
    тут надо иметь ввиду, что в этом случае не отправляются сигналы pre_save и post_save. если у модели есть ресиверы, то без цикла не обойтись


  1. MrNull
    08.10.2025 22:44

    Админка Django, это даже не админка в современном понимании, а какое-то недоразумение, рудимент. Я смотрю на Laravel Nova и Filament и завидую черной завистью. И я не говорю даже о таких инструментах как Laravel Telescope, то вообще какой-то космос. Очень жаль что Django на столько отстал и боюсь что отстал безнадежно.


  1. rSedoy
    08.10.2025 22:44

    А для какой цели в пункте 5 переопределять get_queryset? list_select_related именно это же уже и делает.


  1. Mastermind-S
    08.10.2025 22:44

    А еще можно выкинуть джанго, написать нормальную архитектуру и экономить 500 часов в неделю на команду.


    1. Elendiar1
      08.10.2025 22:44

      Зачем? Админка не заменит полноценный интерактивный spa фронт, но может его дополнить местом конфигурирования/администрирования, избавляя от писанины тонны тривиальных костылей. Она из коробки в пару строк уже позволяет редактировать модели...

      Так то админку с дашбордом можно сделать покрасивее/функциональней с помощью unfold+cotton+htmx


    1. yokotoka
      08.10.2025 22:44

      Выкинув Джанго потратишь 500 часов в неделю, чтобы в итоге написать худшую версию джанги