Налаштування Адмін-панелі Django у 2026 році: Дії, Фільтри та Питання на Співбесідах
Повний посібник з налаштування адмін-панелі Django 6 з користувацькими діями, фільтрами списків, fieldsets та inline моделями. Включає питання для співбесід.

Налаштування адмін-панелі Django перетворює вбудований адміністративний інтерфейс з простого інструменту генерації коду на спеціалізований бек-офіс для виробничих застосунків. Django 6 постачається з покращеними функціями адміністрування, включаючи підрахунок фасетів для фільтрів, налаштовувані форми зміни пароля та іконки Font Awesome, що робить добре налаштовану адмін-панель справді приємною у використанні.
ModelAdmin — це центральний клас для всіх налаштувань адмін-панелі. Опанування list_display, list_filter, search_fields, fieldsets та користувацьких дій дозволяє задовольнити 90% потреб у конфігурації панелі.
Основи ModelAdmin: list_display та search_fields
list_display контролює, які колонки з'являються на сторінці списку змін. Окрім простих назв полів, приймає викликувані функції з декоратором @admin.display() для обчислюваних значень. search_fields активує поле пошуку, яке за замовчуванням фільтрує записи за допомогою icontains.
# admin.py
from django.contrib import admin
from django.utils.html import format_html
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ["title", "author_name", "status", "publish_date", "is_recent"]
search_fields = ["title", "author__email", "content"]
list_per_page = 50
list_select_related = ["author"] # Avoid N+1 queries
@admin.display(description="Author", ordering="author__last_name")
def author_name(self, obj):
return f"{obj.author.first_name} {obj.author.last_name}"
@admin.display(description="Recent?", boolean=True)
def is_recent(self, obj):
from django.utils import timezone
return obj.publish_date >= timezone.now() - timezone.timedelta(days=7)
admin.site.register(Article, ArticleAdmin)Декоратор @admin.display() замінює старіший патерн встановлення short_description як атрибута функції. Параметр boolean=True рендерить іконку галочки або X замість тексту True/False. Використання list_select_related запобігає запитам N+1 при доступі до полів зовнішніх ключів у list_display.
Користувацькі list_filter з SimpleListFilter
list_filter активує фільтри бічної панелі на сторінці списку змін. Назви полів працюють для базової фільтрації, але SimpleListFilter обробляє складну логіку фільтрування, що охоплює кілька полів або вимагає користувацьких запитів.
# admin.py
from datetime import date, timedelta
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from .models import Article
class PublishDateFilter(admin.SimpleListFilter):
title = _("publish period")
parameter_name = "published" # URL parameter: ?published=this_week
def lookups(self, request, model_admin):
# Returns (value, label) tuples for the filter sidebar
return [
("this_week", _("This week")),
("this_month", _("This month")),
("this_year", _("This year")),
("unpublished", _("Not published")),
]
def queryset(self, request, queryset):
# Filter the queryset based on self.value()
today = date.today()
if self.value() == "this_week":
return queryset.filter(publish_date__gte=today - timedelta(days=7))
if self.value() == "this_month":
return queryset.filter(
publish_date__year=today.year, publish_date__month=today.month
)
if self.value() == "this_year":
return queryset.filter(publish_date__year=today.year)
if self.value() == "unpublished":
return queryset.filter(publish_date__isnull=True)
return queryset
class ArticleAdmin(admin.ModelAdmin):
list_filter = [
"status",
PublishDateFilter,
("author", admin.RelatedOnlyFieldListFilter), # Show only authors with articles
]RelatedOnlyFieldListFilter обмежує випадаючий список авторів лише тими, хто дійсно має статті, замість відображення кожного користувача в базі даних. Це покращує зручність використання, коли пов'язана модель має багато записів.
Фасети Django 6: Лічильники Фільтрів на Бічній Панелі
Django 6 представив підрахунок фасетів, який відображає кількість відповідних об'єктів поруч з кожною опцією фільтра. Атрибут show_facets контролює цю поведінку.
# admin.py
from django.contrib import admin
from django.contrib.admin import ShowFacets
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ["title", "status", "category"]
list_filter = ["status", "category", "author"]
show_facets = ShowFacets.ALWAYS # Always display counts
# Alternative values:
# ShowFacets.ALLOW - Show counts when ?_facets=1 in URL
# ShowFacets.NEVER - Never show counts (for large datasets)Лічильники фасетів виконують додаткові запити COUNT для кожної опції фільтра. На таблицях з мільйонами рядків слід встановити show_facets = ShowFacets.NEVER, щоб уникнути зниження продуктивності. Лічильники оновлюються динамічно при застосуванні фільтрів, показуючи скільки записів відповідає поточній комбінації фільтрів.
Користувацькі Адмін-Дії для Масових Операцій
Адміністративні дії виконують масові операції над вибраними об'єктами. Декоратор @admin.action встановлює дозволи та опис, що відображається у випадаючому меню.
# admin.py
from django.contrib import admin
from django.contrib import messages
from django.utils.translation import ngettext
from .models import Article
@admin.action(description="Publish selected articles", permissions=["change"])
def publish_articles(modeladmin, request, queryset):
# Exclude already published articles
unpublished = queryset.exclude(status="published")
updated = unpublished.update(status="published")
modeladmin.message_user(
request,
ngettext(
"%d article was published.",
"%d articles were published.",
updated,
)
% updated,
messages.SUCCESS,
)
@admin.action(description="Export selected as JSON")
def export_as_json(modeladmin, request, queryset):
from django.http import HttpResponse
from django.core import serializers
response = HttpResponse(content_type="application/json")
response["Content-Disposition"] = 'attachment; filename="articles.json"'
serializers.serialize("json", queryset, stream=response)
return response # Returning HttpResponse triggers file download
class ArticleAdmin(admin.ModelAdmin):
actions = [publish_articles, export_as_json]
def get_actions(self, request):
# Conditionally remove actions based on user permissions
actions = super().get_actions(request)
if not request.user.has_perm("articles.delete_article"):
del actions["delete_selected"]
return actionsПовернення HttpResponse з дії ініціює завантаження файлу або перенаправляє на сторінку підтвердження. Параметр permissions обмежує дію користувачами з певними дозволами моделі. Перевизначення get_actions() дозволяє динамічно показувати або приховувати дії на основі поточного запиту.
Готовий до співбесід з Django?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Fieldsets та Inline Моделі для Організованих Форм
fieldsets організовує форми додавання та редагування у розгортувані секції. TabularInline та StackedInline вбудовують пов'язані моделі безпосередньо у батьківську форму, усуваючи навігацію між сторінками.
# admin.py
from django.contrib import admin
from .models import Article, ArticleImage, ArticleComment
class ArticleImageInline(admin.TabularInline):
model = ArticleImage
extra = 1 # Number of empty forms to display
max_num = 5 # Maximum images per article
fields = ["image", "caption", "order"]
class ArticleCommentInline(admin.StackedInline):
model = ArticleComment
extra = 0
readonly_fields = ["created_at", "author"]
can_delete = True
class ArticleAdmin(admin.ModelAdmin):
fieldsets = [
(
None,
{
"fields": ["title", "slug", "author"],
},
),
(
"Content",
{
"fields": ["content", "excerpt"],
"classes": ["wide"], # Full-width fields
},
),
(
"Publishing",
{
"fields": ["status", "publish_date", "category", "tags"],
"classes": ["collapse"], # Collapsed by default
},
),
(
"SEO",
{
"fields": ["meta_title", "meta_description"],
"classes": ["collapse"],
"description": "Search engine optimization fields",
},
),
]
inlines = [ArticleImageInline, ArticleCommentInline]
prepopulated_fields = {"slug": ["title"]} # Auto-generate slug from title
autocomplete_fields = ["author", "category"] # AJAX-powered select
filter_horizontal = ["tags"] # Widget for M2M selection
admin.site.register(Article, ArticleAdmin)TabularInline відображає пов'язані об'єкти у компактному табличному форматі, що підходить для простих моделей з кількома полями. StackedInline показує кожен пов'язаний об'єкт як окремий блок форми, краще підходить для моделей з багатьма полями. Опція autocomplete_fields замінює стандартний випадаючий список на віджет пошуку AJAX, що є необхідним, коли пов'язана модель має тисячі записів.
Налаштування Сайту Адміністрування
Створення підкласу AdminSite дозволяє мати кілька адміністративних інтерфейсів з різним брендингом, дозволами або реєстраціями моделей. Django 6 додав можливість налаштування password_change_form для суворіших політик паролів.
# admin.py
from django.contrib import admin
from django.contrib.admin import AdminSite
from .models import Article, Category
class ContentAdminSite(AdminSite):
site_header = "Content Management"
site_title = "CMS"
index_title = "Dashboard"
def has_permission(self, request):
# Restrict to staff in the 'editors' group
return (
request.user.is_active
and request.user.is_staff
and request.user.groups.filter(name="editors").exists()
)
content_admin = ContentAdminSite(name="content_admin")
content_admin.register(Article, ArticleAdmin)
content_admin.register(Category)
# In urls.py:
# path('content-admin/', content_admin.urls),Кожен екземпляр AdminSite має власний простір імен URL, сторінку входу та набір зареєстрованих моделей. Цей патерн підходить для застосунків з різними ролями користувачів, де редактори не повинні бачити управління користувачами або системні налаштування.
Питання на Співбесідах: Налаштування Адмін-панелі Django
Ці питання часто з'являються на технічних співбесідах з Django. Розуміння базових механізмів, а не лише синтаксису, відрізняє кандидатів середнього рівня від старших інженерів.
П: Як додати обчислювану колонку до list_display, яку не можна сортувати?
Декоратор @admin.display() приймає параметр ordering, який вказує яке поле бази даних використовувати для сортування. Без нього заголовок колонки не є клікабельним. Обчислювані значення, що агрегують кілька записів або викликають зовнішні сервіси, не можуть бути відсортовані, оскільки немає базової колонки бази даних для впорядкування.
П: Який вплив лічильників фасетів на продуктивність і коли їх слід вимикати?
Фасети виконують один запит COUNT на кожну опцію фільтра, помножену на кількість активних фільтрів. На таблиці з 10 мільйонами рядків і 5 опціями фільтра на 3 полях, це 15 додаткових запитів COUNT на кожне завантаження сторінки. Слід встановити show_facets = ShowFacets.NEVER, коли будь-який фільтр націлений на таблицю з більш ніж 100 000 рядків без відповідних індексів.
П: Чим відрізняються адмін-дії від користувацьких представлень адміністратора?
Дії працюють з queryset вибраних об'єктів і інтегруються з прапорцями вибору списку змін. Користувацькі представлення адміністратора — це окремі сторінки, доступні через користувацькі URL, підходять для звітів, імпортів або дашбордів, які не працюють з вибраними записами. Дії не повинні виконувати тривалі операції, оскільки вони блокують запит.
П: Чому використовувати RelatedOnlyFieldListFilter замість стандартного фільтра?
Стандартний RelatedFieldListFilter запитує всі об'єкти в пов'язаній таблиці. Коли зовнішній ключ вказує на модель User зі 100 000 записами, випадаючий список фільтра завантажує всі 100 000 опцій, заморожуючи браузер. RelatedOnlyFieldListFilter запитує лише значення, які існують у записах поточної моделі, зазвичай значно менший набір.
Типові Помилки, Яких Слід Уникати у Виробництві
Кілька патернів, що працюють у розробці, спричиняють проблеми при масштабуванні.
# admin.py
from django.contrib import admin
from .models import Order
class OrderAdmin(admin.ModelAdmin):
# Mistake: Accessing related fields without list_select_related
# This causes N+1 queries, one per row in the list view
list_display = ["id", "customer_email", "total"]
# Fix: Prefetch related objects
list_select_related = ["customer"]
def customer_email(self, obj):
return obj.customer.email
# Mistake: search_fields on unindexed large text columns
# search_fields = ["notes"] # Slow on large tables
# Fix: Limit search to indexed fields
search_fields = ["id", "customer__email"]
# Mistake: Expensive computation in list_display
# def order_total(self, obj):
# return sum(item.price * item.qty for item in obj.items.all()) # N+1
# Fix: Use annotation in get_queryset
def get_queryset(self, request):
from django.db.models import Sum, F
qs = super().get_queryset(request)
return qs.annotate(computed_total=Sum(F("items__price") * F("items__qty")))
@admin.display(description="Total", ordering="computed_total")
def total(self, obj):
return obj.computed_totalПеревизначення get_queryset() для додавання анотацій зберігає обчислювані значення в одному запиті, замість звернення до бази даних один раз на кожен рядок. Профілювання адмін-панелі за допомогою Django Debug Toolbar дозволяє виявити запити N+1 до того, як вони потраплять у виробництво.
Сторонні Теми для Адмін-панелі: Django Unfold
Django Unfold — найактивніше підтримувана тема адміністрування для Django 6, побудована на Tailwind CSS. Вона розширює стандартну адмін-панель, а не замінює її, тому існуючі конфігурації ModelAdmin продовжують працювати.
# settings.py
INSTALLED_APPS = [
"unfold", # Must come before django.contrib.admin
"unfold.contrib.filters", # Advanced filter widgets
"unfold.contrib.forms", # Enhanced form widgets
"django.contrib.admin",
# ...
]Unfold додає темний режим, адаптивні макети, бічну навігацію та розширені типи фільтрів, такі як RangeNumericFilter та RangeDateFilter. Інтеграція HTMX та Alpine.js забезпечує інтерактивність без накладних витрат повноцінного SPA-фреймворку. Для команд, яким потрібна відполірована адмін-панель без створення користувацького дашборду, Unfold економить тижні роботи над фронтендом.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Що Запам'ятати про Налаштування Адмін-панелі Django
list_displayз@admin.display()контролює колонки; додаванняorderingзабезпечує можливість сортування обчислюваних значеньSimpleListFilterобробляє користувацьку логіку фільтрування, що охоплює кілька полів або вимагає діапазонів дат- Фасети Django 6 показують лічильники фільтрів; вимкнення через
ShowFacets.NEVERна великих таблицях дозволяє уникнути накладних витрат на запити COUNT - Адмін-дії з
@admin.action(permissions=[...])обробляють масові операції; поверненняHttpResponseзабезпечує експорт файлів - Використання
list_select_relatedта анотованих queryset уget_queryset()запобігає запитам N+1 у представленнях списків RelatedOnlyFieldListFilterзапобігає зависанню браузера при фільтруванні за зовнішнім ключем до великих таблиць- Практикування цих патернів з питаннями на співбесідах Django, спеціально спрямованими на конфігурацію адмін-панелі
Чи знайдеш ти помилку в Django?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 13 вересня 2026 р.
Поділитися
Пов'язані статті

Просунуте Middleware в Django 2026: Створення Власних Middleware, Логування та Питання на Співбесідах
Повний посібник з просунутих технік middleware в Django 2026. Дізнайтеся, як створювати власні middleware, імплементувати логування та підготуватися до технічних співбесід.

Django Signals vs Celery Tasks у 2026: Коли Використовувати та Питання на Співбесіді
Комплексне порівняння Django Signals та Celery Tasks у 2026 році. Коли використовувати сигнали, а коли асинхронні задачі, з прикладами коду та питаннями на технічну співбесіду.

Django Channels у 2026: WebSocketи, Комунікація в Реальному Часі та Питання на Співбесіді
Django Channels 4.x розширює Django за межі HTTP, забезпечуючи підтримку WebSocketів та функцій реального часу, таких як чат, сповіщення та живі дашборди.