Personalização do Admin Django em 2026: Actions, Filtros e Perguntas de Entrevista
Guia completo sobre a personalização da interface de administração do Django em 2026. Actions personalizadas, filtros avançados e perguntas técnicas de entrevista para desenvolvedores Django.

A interface de administração do Django permanece como um dos recursos mais valiosos do framework em 2026. Essa funcionalidade integrada permite que desenvolvedores criem rapidamente interfaces de gestão de dados sem necessidade de escrever código frontend. Entretanto, para requisitos de negócio específicos, a personalização se torna indispensável. Este guia explora as técnicas avançadas de personalização do admin Django, incluindo actions personalizadas, filtros sofisticados e as perguntas mais frequentes em entrevistas técnicas.
A personalização do admin Django permite economizar centenas de horas de desenvolvimento enquanto oferece uma experiência de usuário otimizada para gestores de conteúdo.
Configuração Base do Admin Django
Antes de explorar as personalizações avançadas, é necessário compreender a configuração fundamental. O Django 5.x introduz diversas melhorias notáveis na interface de administração.
from django.contrib import admin
from django.contrib.admin import AdminSite
from .models import Article, Category, Author
class CustomAdminSite(AdminSite):
site_header = "Painel de Administração"
site_title = "Admin Portal"
index_title = "Gestão de Conteúdo"
admin_site = CustomAdminSite(name='custom_admin')
@admin.register(Article, site=admin_site)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'status', 'published_at', 'view_count']
list_filter = ['status', 'category', 'published_at']
search_fields = ['title', 'content', 'author__name']
date_hierarchy = 'published_at'
ordering = ['-published_at']Essa configuração estabelece as bases de uma interface de administração personalizada com um cabeçalho distintivo e opções de filtragem essenciais.
Actions Personalizadas no Admin Django
As actions personalizadas permitem realizar operações em massa nos objetos selecionados. Essa funcionalidade se mostra particularmente útil para fluxos de trabalho editoriais.
from django.contrib import admin, messages
from django.utils import timezone
from django.core.mail import send_mass_mail
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'status', 'published_at']
actions = ['publish_articles', 'archive_articles', 'notify_authors']
@admin.action(description="Publicar artigos selecionados")
def publish_articles(self, request, queryset):
updated = queryset.filter(status='draft').update(
status='published',
published_at=timezone.now()
)
self.message_user(
request,
f"{updated} artigo(s) publicado(s) com sucesso.",
messages.SUCCESS
)
@admin.action(description="Arquivar artigos selecionados")
def archive_articles(self, request, queryset):
queryset.update(status='archived', archived_at=timezone.now())
self.message_user(request, "Artigos arquivados.", messages.WARNING)
@admin.action(description="Notificar os autores")
def notify_authors(self, request, queryset):
emails = []
for article in queryset.select_related('author'):
if article.author.email:
emails.append((
f"Atualização: {article.title}",
f"Seu artigo '{article.title}' foi atualizado.",
'noreply@example.com',
[article.author.email]
))
send_mass_mail(emails, fail_silently=True)
self.message_user(request, f"{len(emails)} notificação(ões) enviada(s).")As actions com confirmação fornecem uma camada adicional de segurança para operações críticas.
from django.contrib.admin import helpers
from django.template.response import TemplateResponse
@admin.action(description="Excluir permanentemente com confirmação")
def delete_permanently(self, request, queryset):
if request.POST.get('confirm'):
count = queryset.count()
queryset.delete()
self.message_user(request, f"{count} elemento(s) excluído(s) permanentemente.")
return None
context = {
**self.admin_site.each_context(request),
'title': 'Confirmar exclusão',
'queryset': queryset,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
}
return TemplateResponse(request, 'admin/confirm_delete.html', context)Filtros Personalizados Avançados
Os filtros padrão do Django cobrem os casos de uso comuns, porém projetos complexos frequentemente necessitam de filtros customizados.
from django.contrib.admin import SimpleListFilter
from django.utils import timezone
from datetime import timedelta
class PublicationStatusFilter(SimpleListFilter):
title = 'Status de publicação'
parameter_name = 'pub_status'
def lookups(self, request, model_admin):
return [
('recent', 'Publicado recentemente (7 dias)'),
('this_month', 'Este mês'),
('scheduled', 'Agendado'),
('needs_review', 'Necessita revisão'),
]
def queryset(self, request, queryset):
now = timezone.now()
if self.value() == 'recent':
return queryset.filter(
status='published',
published_at__gte=now - timedelta(days=7)
)
elif self.value() == 'this_month':
return queryset.filter(
status='published',
published_at__month=now.month,
published_at__year=now.year
)
elif self.value() == 'scheduled':
return queryset.filter(
status='scheduled',
published_at__gt=now
)
elif self.value() == 'needs_review':
return queryset.filter(
status='draft',
updated_at__lt=now - timedelta(days=30)
)
return queryset
class AuthorActivityFilter(SimpleListFilter):
title = 'Atividade do autor'
parameter_name = 'author_activity'
def lookups(self, request, model_admin):
return [
('active', 'Autores ativos'),
('inactive', 'Autores inativos'),
('top', 'Principais contribuidores'),
]
def queryset(self, request, queryset):
from django.db.models import Count
if self.value() == 'active':
active_authors = Author.objects.filter(
articles__published_at__gte=timezone.now() - timedelta(days=90)
).values_list('id', flat=True)
return queryset.filter(author_id__in=active_authors)
elif self.value() == 'top':
top_authors = Author.objects.annotate(
article_count=Count('articles')
).filter(article_count__gte=10).values_list('id', flat=True)
return queryset.filter(author_id__in=top_authors)
return querysetA integração desses filtros no admin é realizada de forma simples.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'status', 'published_at', 'view_count']
list_filter = [
PublicationStatusFilter,
AuthorActivityFilter,
'category',
('published_at', admin.DateFieldListFilter),
]Personalização da Visualização e dos Formulários
A melhoria da experiência do usuário requer a personalização de formulários e visualização.
from django import forms
from django.utils.html import format_html
from django.urls import reverse
class ArticleAdminForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
widgets = {
'content': forms.Textarea(attrs={
'rows': 20,
'class': 'vLargeTextField'
}),
'summary': forms.Textarea(attrs={'rows': 3}),
}
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 10:
raise forms.ValidationError(
"O título deve conter pelo menos 10 caracteres."
)
return title
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
form = ArticleAdminForm
list_display = ['title', 'author_link', 'status_badge', 'published_at', 'view_count']
readonly_fields = ['created_at', 'updated_at', 'preview_link']
fieldsets = [
('Informações principais', {
'fields': ['title', 'slug', 'author', 'category']
}),
('Conteúdo', {
'fields': ['summary', 'content', 'featured_image'],
'classes': ['wide']
}),
('Publicação', {
'fields': ['status', 'published_at', 'is_featured'],
'classes': ['collapse']
}),
('Metadados', {
'fields': ['created_at', 'updated_at', 'preview_link'],
'classes': ['collapse']
}),
]
@admin.display(description='Autor')
def author_link(self, obj):
url = reverse('admin:blog_author_change', args=[obj.author.pk])
return format_html('<a href="{}">{}</a>', url, obj.author.name)
@admin.display(description='Status')
def status_badge(self, obj):
colors = {
'draft': '#ffc107',
'published': '#28a745',
'archived': '#6c757d'
}
color = colors.get(obj.status, '#17a2b8')
return format_html(
'<span style="background: {}; color: white; padding: 3px 10px; '
'border-radius: 3px;">{}</span>',
color, obj.get_status_display()
)
@admin.display(description='Visualização')
def preview_link(self, obj):
if obj.pk:
url = obj.get_absolute_url()
return format_html(
'<a href="{}" target="_blank" class="button">Ver visualização</a>',
url
)
return "-"Otimização de Performance
Para projetos com grandes volumes de dados, a otimização de consultas se torna crucial.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'category', 'status']
list_select_related = ['author', 'category']
list_prefetch_related = ['tags']
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('author', 'category').prefetch_related('tags')
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(
request, queryset, search_term
)
# Busca otimizada com índices
if search_term:
queryset = queryset.filter(
title__icontains=search_term
) | queryset.filter(
content__icontains=search_term
)
return queryset, use_distinctPerguntas de Entrevista sobre o Admin Django
Durante entrevistas técnicas para posições de desenvolvimento Django, o domínio da interface de administração é frequentemente avaliado. A seguir estão as perguntas mais comuns.
Pergunta 1: Como restringir o acesso a determinados campos de acordo com o papel do usuário?
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if not request.user.is_superuser:
return ['author', 'published_at', 'view_count']
return []
def get_fieldsets(self, request, obj=None):
fieldsets = super().get_fieldsets(request, obj)
if not request.user.has_perm('blog.can_publish'):
# Ocultar seção de publicação para não editores
fieldsets = [fs for fs in fieldsets if fs[0] != 'Publicação']
return fieldsets
def has_delete_permission(self, request, obj=None):
if obj and obj.status == 'published':
return request.user.is_superuser
return super().has_delete_permission(request, obj)Pergunta 2: Como implementar um sistema de auditoria no admin?
from django.contrib.admin.models import LogEntry, CHANGE
from django.contrib.contenttypes.models import ContentType
class AuditableAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if change:
obj.modified_by = request.user
else:
obj.created_by = request.user
super().save_model(request, obj, form, change)
def log_change(self, request, obj, message):
super().log_change(request, obj, message)
# Log personalizado adicional
AuditLog.objects.create(
user=request.user,
action='change',
model_name=obj._meta.model_name,
object_id=obj.pk,
changes=str(message)
)Pergunta 3: Como criar um widget de autocomplete personalizado?
from django.contrib.admin.widgets import AutocompleteSelect
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
autocomplete_fields = ['author', 'category']
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'author':
kwargs['queryset'] = Author.objects.filter(is_active=True)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
search_fields = ['name', 'email']
ordering = ['name']Pronto para mandar bem nas entrevistas de Django?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
Boas Práticas e Recomendações
A personalização eficaz do admin Django se fundamenta em vários princípios essenciais. A separação de responsabilidades garante uma manutenção simplificada do código. Os filtros e actions devem permanecer simples e performáticos, evitando consultas N+1 através de select_related e prefetch_related.
O uso apropriado das permissões do Django permite criar interfaces adaptadas a cada papel de usuário. Os testes unitários para actions personalizadas asseguram a confiabilidade das operações em massa.
Por fim, a documentação das personalizações facilita a integração de novos desenvolvedores e a manutenção de longo prazo do projeto.
Conclusão
A interface de administração do Django oferece uma flexibilidade notável para atender aos requisitos de negócio mais diversos. As actions personalizadas, filtros avançados e técnicas de otimização apresentadas neste guia constituem uma base sólida para qualquer projeto Django profissional. O domínio desses conceitos representa uma vantagem significativa durante entrevistas técnicas e na prática diária do desenvolvimento Django.
Você saberia encontrar o bug em Django?
Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Escrito por
Anthony Fillion-MailletFundador da SharpSkill
Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.
Atualizado em 13 de setembro de 2026
Compartilhar
Artigos relacionados

Middleware Avançado no Django 2026: Middleware Personalizado, Logging e Perguntas de Entrevista
Guia completo sobre middleware avançado no Django 2026. Criação de middleware personalizado, logging estruturado, tratamento de erros e perguntas de entrevista técnica para desenvolvedores Python.

Django Signals vs Celery Tasks em 2026: Quando Usar Cada Um e Perguntas de Entrevista
Aprenda quando usar signals Django versus tasks Celery. Aborda o tratamento de eventos síncrono vs assíncrono, implicações de performance e perguntas de entrevista para desenvolvedores Django.

Django Channels em 2026: WebSockets, Tempo Real e Perguntas de Entrevista
Guia completo sobre Django Channels 4.x para WebSockets e comunicação em tempo real. Configuração do Redis, consumers async e perguntas de entrevista técnica.