O site admin do Django

Uma das mais poderosas partes do Django é a inteface de administração automática. Ela lê os metadados de seu model para fornecer uma inteface poderosa e pronta para produção que produtores de conteúdo podem imediatamente usar para começar a adicionar conteúdos ao site. Neste documento, nós discutimos como ativar, usar e personalizar a interface de administração do Django.

Nota

O site admin foi significantemente refatorado desde a versão 0.96. Este documento descreve a versão mais nova do site admin, que permite customizações mais ricas. Se você acompanha o desenvolvimento do Django em si, você pode ter ouvido isso descrito como “newforms-admin.”

Visão geral

Há cinco passos para ativar o site admin do Django:

  1. Adicione django.contrib.admin no seu INSTALLED_APPS.
  2. Determine quais models de aplicações devem ser editados pela interface admin.
  3. Para cada um destes models, opicionalmente, crie uma classe ModelAdmin que encapsula as funcionalidades customizadas do admin e opções para este model particular.
  4. Instancie um AdminSite e o informe sobre cada um de seus models e classes ModelAdmin.
  5. Ligue a instância AdminSite ao seu URLconf.

See also

Para informações sobre como servir arquivos de mídia (imagens, JavaScript, e CSS) associado ao admin em produção, veja Servindo arquivos de mídia.

Objetos ModelAdmin

class ModelAdmin

A classe ModelAdmin é a representação de um model na interface de administração. Este são armazenados num arquivo chamado admin.py na sua aplicação. Vamos dar uma olhada num exemplo muito simples de ModelAdmin:

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

Você precisa de um objeto ModelAdmin sempre?

No exemplo anterior, a classe ModelAdmin não define quaisquer valores personalizados (ainda). Como um resultado, a interface admin padrão será fornecida. Se você estiver feliz com a interface admin padrão, você não precisa definir um objeto ModelAdmin sempre – você poder registrar a classe model sem fornecer uma descrição do ModelAdmin. O exemplo anterior poderia ser simplicado para:

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)

Opções ModelAdmin

O ModelAdmin é muito flexível. Ele tem várias opções para lidar com customização da interface. Todas as opções são definidas na subclasse ModelAdmin:

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'
ModelAdmin.date_hierarchy

Sete o date_hierarchy com o nome de um DateField ou DateTimeField do seu model, e a lista de dados incluirá uma navegação por data, utilizando o campo informado.

Exemplo:

date_hierarchy = 'pub_date'
ModelAdmin.form

Por padrão um ModelForm é dinamicamente criado para seu model. Ele é usado para criar o formulário apresentado em ambas as páginas adicionar/editar. Você pode facilmente fornecer seu próprio ModelForm para sobrescrever qualquer comportamento de formulário nas páginas adicionar/editar.

Para um exemplo veja a seção Adicionando validação personalizada ao admin.

ModelAdmin.fieldsets

Sete fieldsets para controlar o layout das páginas “adicionar” e “editar” do admin.

fieldsets é uma lista de tuplas duplas, em que cada tupla dupla representa um <fieldset> sobre a página de formulário do admin. (Um <fieldset> é uma “seção” do formulário.)

As tuplas duplas estão no formato (name, field_options), onde name é uma string representando o título do fieldset e field_options é um dicionário com informações sobre o fieldset, incluíndo uma lista de campos para serem mostrados nele.

Um exemplo completo, recebido do model django.contrib.flatpages.FlatPage:

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('enable_comments', 'registration_required', 'template_name')
        }),
    )

Isso resulta numa página admin que parece com:

../../_images/flatfiles_admin.png

Se o fieldsets não for fornecido, o Django mostrará o padrão de cada campo que não for um AutoField e tenha um editable=True, em um fieldset único, na mesma ordem em que os campos foram definidos no model.

O dicionário field_optinos pode ter as seguintes chaves:

  • fields

    Uma tupla com nomes de campos que serão mostrados no fieldset. Esta chave é obrigatória.

    Exemplo:

    {
    'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
    }
    

    Para mostrar vários campos na mesma linha, envolva-os em suas próprias tuplas. Neste exemplo, os campos first_name e last_name serão mostrados na mesma linha:

    {
    'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
    }
    
  • classes

    Uma lista contendo classes extra de CSS para serem aplicadas ao fieldset.

    Exemplo:

    {
    'classes': ['wide', 'extrapretty'],
    }
    

    Duas classes úteis definidas por padrão no site admin são collapse e wide. Os fieldsets com o estilo collapse serão inicialmente encolhidos no admin e substituídos por um link “click para expandir”. Os fieldsets com o estilo wide ocuparão um espaço horizontal extra.

  • description

    Uma string de texto opcional extra para ser mostrado no topo de cada fieldset, abaixo do cabeçalho do fieldset.

    Note que este valor não tem o HTML escapado quando é mostrado na interface do admin. Isso permite você incluir HTML se assim desejar. Aleternativamente você poder usar texto plano e django.utils.html.escape() para escapar quaisquer caracteres especiais de HTML.

ModelAdmin.fields

Use esta opção como uma alternativa ao fieldsets se o layout não importar e se você deseja somente mostrar um sub-conjunto de campos disponíveis no formulário. Por exemplo, você poderia definir uma versão mais simples do formulário do admin para o model django.contrib.flatpages.FlatPage desta forma:

class FlatPageAdmin(admin.ModelAdmin):
    fields = ('url', 'title', 'content')

No exemplo acima, somente os campos ‘url’, ‘title’ e ‘content’ serão mostrados, sequencialmente, no formulário.

Nota

Estas opções fields não devem ser confundidas com a chave de dicionário fields que fica dentro da opção fieldsets, como descrito na seção anterior.

ModelAdmin.exclude

Este atributo, se fornecido, deve ser uma lista com nomes de campos a se escluir do formulário.

Por exemplo, vamos considerar o seguinte model:

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3)
    birth_date = models.DateField(blank=True, null=True)

Se você deseja um formulário do model Author que inclui somente os campos name e title, você poderia especificar fields ou exclude desta forma:

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title')

class AuthorAdmin(admin.ModelAdmin):
    exclude = ('birth_date',)

Assim o model Author somente terá três campos, name, title, e birth_date, os formulários resultantes das declarações acima conterão extamante os mesmos campos.

ModelAdmin.filter_horizontal

Use a nifty unobtrusive JavaScript “filter” interface instead of the usability-challenged <select multiple> in the admin form. The value is a list of fields that should be displayed as a horizontal filter interface. See filter_vertical to use a vertical interface.

ModelAdmin.filter_vertical

O mesmo que filter_horizontal, mas é um display vertical do filtro.

ModelAdmin.list_display

Configure o list_display para controlar quais campos são mostrados na listagem do admin.

Exemplo:

list_display = ('first_name', 'last_name')

Se você não seta list_display, o site admin mostrará uma única coluna que mostra o __unicode__() representando cada objeto.

Você tem quatro valores possível que podem ser usado no list_display:

  • Uma campo de model. Por exemplo:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • Uma função que aceita um paramêtro para a instância do model. Por exemplo:

    def upper_case_name(obj):
        return ("%s %s" % (obj.first_name, obj.last_name)).upper()
    upper_case_name.short_description = 'Name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • Uma string representando um atributo no ModelAdmin. Este se comporta da mesma forma que a função acima. Por exemplo:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        def upper_case_name(self, obj):
          return ("%s %s" % (obj.first_name, obj.last_name)).upper()
        upper_case_name.short_description = 'Name'
    
  • Uma string representando um atributo no model. Este se comporta quase como a função acima, a diferença é que o self neste contexto é a instância do model. Aqui temos um exemplo completo:

    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return self.birthday.strftime('%Y')[:3] + "0's"
        decade_born_in.short_description = 'Birth decade'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

Uns poucos casos especiais para se tomar nota sobre o list_display:

* Se o campo é um ``ForeignKey``, o Django mostrará o ``__unicode`__()`` do
  objeto relacionado.

* Campos ``ManyToManyField`` não são suportados, pois poderiam implicar em
execução de consultas SQL em separado pra cada linha da tabela. Se você
deseja fazer isso de qualquer forma, dê ao seu model um método
personalizado, e adicione o nome desse método no ``list_display``. (Veja
abaixo para saber mais sobre métodos personalizados no ``list_display``.)

* Se o campo é um ``BooleanField`` ou ``NullBooleanField``, o Django
  mostrará um belo ícone "on" ou "off" ao invés de ``True`` ou ``False``.

* Se a string fornecida é um método do model, ``ModelAdmin`` ou uma função,
  o Django espacará o HTML da saída por padrão. Se você gostaria de não
  escapar a saída do método, de ao método um atributo ``allow_tags`` cujo o
  valor é ``True``.

  Aqui temos um exemplo completo::

      class Person(models.Model):
          first_name = models.CharField(max_length=50)
          last_name = models.CharField(max_length=50)
          color_code = models.CharField(max_length=6)

          def colored_name(self):
              return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)
          colored_name.allow_tags = True

      class PersonAdmin(admin.ModelAdmin):
          list_display = ('first_name', 'last_name', 'colored_name')

* Se a string dada é um método do model, ``ModelAdmin`` ou uma função que
  retorna True ou False o Django mostrará um belo ícone "on" ou "off" se
  você der ao método um atributo ``boolean`` cujo o valor é ``True``.

  Aqui temos um exemplo completo do model::

      class Person(models.Model):
          first_name = models.CharField(max_length=50)
          birthday = models.DateField()

          def born_in_fifties(self):
              return self.birthday.strftime('%Y')[:3] == '195'
          born_in_fifties.boolean = True

      class PersonAdmin(admin.ModelAdmin):
          list_display = ('name', 'born_in_fifties')

* Os métodos ``__str__()`` e ``__unicode__()`` não só são válidos no
  ``list_display`` como em qualquer outro método de model, então é
  perfeitamente OK usar isso::

      list_display = ('__unicode__', 'some_other_field')

* Normalmente, os elementos do ``list_display`` que não estão dentre os
  campos do bancos de dados atual não podem ser usado em ordenamentos (pois
  o Django não sabe como sortealos a nível de banco de dados).

  Entretanto, se um elemento de um ``list_display`` representa um certo
  campo do banco de dados, você pode indicar este fato configurando o
  atributo ``admin_order_field`` do item.

  Por exemplo::

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)

        def colored_first_name(self):
            return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
        colored_first_name.allow_tags = True
        colored_first_name.admin_order_field = 'first_name'

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')

  O exemplo acima dirá ao Django para ordenar o campo ``first_name`` quando
  tentar sortear pelo ``colored_first_name`` no admin.

Seta um list_display_links para controlar quais campos no list_display deveriam ser linkados à página de edição de um objeto.

Por padrão, a página de listagem linkará a primeira coluna – o primeiro campo especificado no list_display – para a página de edição de cada item. Mas list_display_links permite você mudar quais colunas serão linkadas. Configure list_display_links com uma lista de tuplas com nomes de campos (no mesmo formato como list_display) para linkar.

O list_display_links pode especificar um ou mais nomes de campos. Tantos quanto os nomes dos campos que aparecerem no list_display, o Django não se preocupa com quantos campos (ou quão poucos) serão linkados. O único requisito é: Se você usar list_display_links, você deve definir list_display.

Neste exemplo, os campos first_name e last_name serão linkados na página de listagem:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'birthday')
    list_display_links = ('first_name', 'last_name')
ModelAdmin.list_filter

Configure o list_filter para ativar os filtros na barra à direita da listagem do admin. Este deve ser uma lista de nomes de campos, e cada campo especificado devem ser BooleanField, CharField, DateField, DateTimeField, IntegerField ou ForeignKey.

Este exemplo, pêgo do model django.contrib.auth.models.User, mostra como ambos list_display e list_filter funcionam:

class UserAdmin(admin.ModelAdmin):
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    list_filter = ('is_staff', 'is_superuser')

O código acima resulta numa página de listagem do admim que parece com este:

../../_images/users_changelist.png

(Este exemplo tem um search_fields definido. Veja abaixo.)

ModelAdmin.list_per_page

Configure o list_per_page para controlar quantos ítens devem aparecer em cada página da paginação da listagem. Por padrão, é setado para 100.

Configure list_select_related para dizer ao Django para usar select_related() na lista de objetos recebida na listagem do admin. Isso pode poupar um monte de consultas no banco de dados.

O valor deve ser True ou False. O padrão é False.

Note que o Django usará select_related(), indiferente desta configuração, se um dos campos no list_display for um ForeignKey.

Para mais sobre select_related(), veja a documentação do select_related().

ModelAdmin.inlines

Veja objetos InlineModelAdmin abaixo.

ModelAdmin.ordering

Configure ordering para especificar como os objetos na listagem do admin devem ser ordenados. Este deve ser uma lista de tuplas no mesmo formato do parâmetro ordering do model.

Se este não for fornecido, o Django admin usará o ordenamento padrão do model.

Nota

O Django somente honra o primeiro elemento na lista/tupla; qualquer outro será ignorado.

ModelAdmin.prepopulated_fields

Configure prepopulated_fields com um mapeamento num dicionário com os campos que devem ser pré-populados a partir de outro campo:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

Quando configurado, os campos dados usaram um pouco de JavaScript para popular os campos atribuídos. O principal uso para esta funcionalidade é a de automaticamente gerar um valor para campos SlugField a partir de um ou mais campos. O valor gerado é produzido concatenando os valores do campo originário, e então transformando este resultado num slug válido (e.g. substituíndo barras por espaços).

O prepopulated_fields não aceita campos DateTimeField, ForeignKey, nem ManyToManyField.

ModelAdmin.radio_fields

Por padrão, o admin do Django usa uma interface com select-box (<select>) para campos que são ForeignKey ou que tem choices configurado. Se um campo é apresentado no radio_fields, o Django usará uma interface com radio-button ao invés. Assumindo que group é um ForeignKey no model Person:

class PersonAdmin(admin.ModelAdmin):
    radio_fields = {"group": admin.VERTICAL}

Você tem a escolha de usar HORIZONTAL ou VERTICAL do módulo django.contrib.admin.

Não inclua um campo no radio_fields a menos que seja um ForeignKey ou tenha choices setado.

ModelAdmin.raw_id_fields

Por padrão, o admin do Django usa um select-box (<select>) para campos que são ForeignKey. Algumas vezes você pode não desejar ficar sujeito a um overhead ao selecionar todos as instâncias relacionadas num drop-down.

O raw_id_fields é uma lista de campos que você gostaria de mudar dentro de um widget Input tanto para ForeignKey quanto ManyToManyField:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ("newspaper",)
ModelAdmin.save_as

Seta save_as para habilitar um “save as” no formulário de edição do admin.

Normalmente, objetos tem três opções de salve: “Salvar”, “Salvar e continuar editando” e “Salvar e adicionar outro”. Se save_as for True, o “Salvar e adicionar outro” será substituído por um botão “Salvar como”.

Nota do tradutor

Se você não estiver utilizando uma versão do Django traduzida, os botões “Salvar e continuar editando”, “Salvar”, “Salvar e adicionar outro” e “Salvar como”, serão, respectivamente, “Save”, “Save and continue editing”, “Save and add another” e “Save as”.

“Salvar como” significa que o objeto será salvo como um novo objeto (com um novo ID), ao invés de um objeto já existente.

Por padrão, save_as é setado como False.

ModelAdmin.save_on_top

Seta save_on_top para adicionar os botões de salvar no topo do formulário de edição do admin.

Normalmente, os botões salvar aparecem somente na base do formulário. Se você setar save_on_top, os botões aparecerão em ambos os lugares, na base e no topo.

Por padrão, save_on_top é setado como False.

ModelAdmin.search_fields

Configure search_fields para habilitar uma caixa de busca na página de listagem do admin. Este deve ser configurado com uma lista de nomes de campos que serão afetados pela busca, sempre que alguém submeter um texto por esta caixa de texto.

Estes campos devem ser algum tipo de campo de texto, como CharField ou TextField. Você pode também executar uma pesquisa relacionada a ForeignKey com a lookup API “siga” a notação:

search_fields = ['foreign_key__related_fieldname']

Quando alguém faz uma busca pelo admin, o Django divide a consulta em palavras e retorna todos os objetos que contém cada uma das palavras, diferenciando maiúsculas, onde pelo menos uma das palavras deve estar no search_fields. Por exemplo, se search_fields é setado para ['first_name', 'last_name'] e um usuário procura por john lennon, o Django fará o equivalente a esta clausula SQL WHERE:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

Para buscas mais rápidas e/ou mais restritivas, prefixe o nome do campo com um operador:

^

Combina com o início do campo. Por exemplo, se search_fields é setado para ['^first_name', '^last_name'] e um usuário procurar por john lennon, o Django fará o equivalente a clausula SQL WHERE:

WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

Esta consulta é mais eficiente que a normal '%john%', pois o banco de dados somente precisa checar o início dos dados da coluna, ao invés de procurar através de todo ele. Ainda mais, se a coluna tem um index nela, alguns bancos de dados podem ser capazes de usar o index para esta consulta, mesmo sendo uma consulta LIKE.

=

Combina exatamente, não diferencia maiúsculas. Por exemplo, se search_fields for configurado para ['=first_name', '=last_name'] e um usuário procura por john lennon, o Django fará o equivalente a clausula SQL WHERE:

WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

Note que a entrada da consulta é dividida nos espaços, então, seguindo este exemplo, atualmente não é possível procurar por todos os dados em que first_name é exatamente 'john winston' (contendo espaço).

@
Executa uma combinação full-text. Essa é como o método de procura padrão, mas usa um index. Atualmente isso só está desponível para MySQL.
ModelAdmin.change_list_template

Caminho para um template personalizado que será usado pelos objetos model na visão de “listagem”. Os templates podem sobrescrever ou extender os templates de base do admin como descrito em Sobrescrevendo Templates do Admin.

Se você não especificar este atributo, um template padrão é entregue com o Django que fornece a aparência padrão do admin.

ModelAdmin.change_form_template

Caminho para o template personalizado que será usado na visão de criação e edição de um objeto model. Os templates podem sobrescrever ou extender os templates de base do admin como descrito em Sobrescrevendo Templates do Admin.

Se você não especificar este atributo, um template padrão é entregue com o Django que fornece a aparência padrão do admin.

ModelAdmin.object_history_template

Caminho para um template que será usado na visão de histórico do objeto model. Os templates podem sobrescrever ou extender os templates de base do admin como descrito em Sobrescrevendo Templates do Admin.

Se você não especificar este atributo, um template padrão é entregue com o Django que fornece a aparência padrão do admin.

ModelAdmin.delete_confirmation_template

Caminho para um template personalizado que será usado pela visão responsável por mostrar a confirmação de exclusão de um ou mais objetos. Os templates podem sobrescrever ou extender os templates de base do admin como descrito em Sobrescrevendo Templates do Admin.

Se você não especificar este atributo, um template padrão é entregue com o Django que fornece a aparência padrão do admin.

Métodos do ModelAdmin

ModelAdmin.save_model(self, request, obj, form, change)

O método save_model recebe o HttpRequest, uma intância do model, uma instância de ModelForm e um valor booleano indicando se está adicionando ou editando um objeto. Aqui você pode fazer quaisquer operações pré ou pós salvamento.

Por exemplo, para atachar request.user ao objeto antes de salvá-lo:

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
ModelAdmin.save_formset(self, request, form, formset, change)

O método save_formset recebe o HttpRequest, a instância do ModelForm pai e um valor booleano que indica se está adicionando ou editando um objeto pai.

Pro exemplo para atachar request.user a cada instância de formset de mudança:

class ArticleAdmin(admin.ModelAdmin):
    def save_formset(self, request, form, formset, change):
        instances = formset.save(commit=False)
        for instance in instances:
            instance.user = request.user
            instance.save()
        formset.save_m2m()

Outros métodos

ModelAdmin.add_view(self, request, form_url='', extra_context=None)

Um view do Django para a página de inclusão de instância de model. Veja a nota abaixo.

ModelAdmin.change_view(self, request, object_id, extra_context=None)

Um view do Django para a página de edição de instância de model. Veja nota abaixo.

ModelAdmin.changelist_view(self, request, extra_context=None)

Um view do Django para página de listagem/ações de instância de model. Veja nota abaixo.

ModelAdmin.delete_view(self, request, object_id, extra_context=None)

Um view do Django para página de confirmação de exclusão de instância e model. Veja nota abaixo.

ModelAdmin.history_view(self, request, object_id, extra_context=None)

Um view do Django para a página que mostra o histórico de modificações de uma instância de model.

Diferentemente dos métodos tipo hook do ModelAdmin detalhados na seção anterior, estes cinco métodos são na verdade, projetados para serem invocados como views do Django pelo URL dispatcher da aplicação admin que renderizam páginas com instâncias de model para operações CRUD. Como resultado, a completa sobrescrita destes métodos mudará o comportamento da aplicação admin.

Uma razão comum para sobrescrever estes métodos é para aumentar o contexto dos dados que são fornecidos para o template que renderiza o view. No exemplo a seguir, o view de edição é sobrescrito de modo que ao template renderizado é fornecido alguns dados extras que caso contrário não estariam disponíveis:

class MyModelAdmin(admin.ModelAdmin):

    # Um template para um view bastante personalizada:
    change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'

    def get_osm_info(self):
        # ...

    def change_view(self, request, object_id, extra_context=None):
        my_context = {
            'osm_data': self.get_osm_info(),
        }
        return super(MyModelAdmin, self).change_view(request, object_id,
            extra_context=my_context)

Definições de mídia ModelAdmin

Tem vezes em que você gostaria de adicionar um pouco de CSS e/ou JavaScript aos views adicionar/editar. Isso pode ser realizado usando uma classe interna Media no seu ModelAdmin:

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        css = {
            "all": ("my_styles.css",)
        }
        js = ("my_code.js",)

Tenha em mente que este será prefixado com MEDIA_URL. A mesma regra se aplica nas regras de definições de mídia em formulários.

Adicionando validação personalizada ao admin

Adicionando validação personalizada de dados no admin é bem simples. A interface automática de administração reusa o django.forms, e a classe ModelAdmin tem a mesma abilidade de definir seu próprio formulário:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

O MyArticleAdminForm pode ser definido em qualquer lugar dentro de seu caminho de import. Agora com seu form você pode adicionar sua própria validação para qualquer campo:

class MyArticleAdminForm(forms.ModelForm):
    class Meta:
        model = Article

    def clean_name(self):
        # faça algo que valide seus dados
        return self.cleaned_data["name"]

É importante usar um ModelForm aqui, caso contrário algo pode não funcionar. Veja a documentação forms em valização personalizada e, mais especificamente, o notas de validação de formulários para mais informações.

Objetos InlineModelAdmin

A interface admin tem a abilidade de editar models na mesma página de um model pai. Este são chamados de inlines. Suponhamos que você tenha dois models:

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author)
   title = models.CharField(max_length=100)

Você pode editar os livros escritos por um autor na página do autor. Você pode adicionar inlines ao seu model para especificá-los em um ModelAdmin.inlines:

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

O Django fornece duas subclasses ao InlineModelAdmin e elas são:

  • TabularInline
  • StackedInline

A diferença entre estas duas é meramente o template utilizado para renderizá-las.

Opções InlineModelAdmin

A classe InilneModelAdmin é uma subclasse de ModelAdmin de modo que ele herda todas as mesmas funcionalidades assim como as suas próprias:

model

O model em que o inline é usado. Este é obrigatório.

fk_name

O nome da chave estrangeira no model. Na maioria dos casos este será tratado de forma automática, mas fk_name deve ser especificada explicitamente se houver mais de uma chave estrangeira para o mesmo model pai.

formset

O padrão para BaseInlineFormSet. Usar seu próprio formset pode dar a você muitas possibilidades de personalização. Inlines são embutidos a volta de model formsets.

form

O valor para form padrão para BaseModelForm. Este é o que é passado através do formset_factory quando está criando o formset para este inline.

extra

Este controla o número de formulários extra que um formset mostrará além dos formulário inciais. Veja a documentação dos formsets para mais informações.

max_num

Este controla o número máximo de formulários que serão mostrados num inline. Este não é diretamente correlacionado ao número de objetos, mas pode ser se o valor for pequeno o suficiente. Veja Limitando o número de objetos editáveis para mais informações.

raw_id_fields

Por padrão, o admin do Django usa um select-box (<select>) para campos que são ForeignKey. Algumas vezes você pode não desejar ficar sujeito a um overhead ao selecionar todos as instâncias relacionadas num drop-down.

O raw_id_fields é uma lista de campos que você gostaria de mudar dentro de um widget Input tanto para ForeignKey quanto para ManuToManyField:

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ("pages",)

template

O template usado para renderizar o inline na página.

verbose_name

Uma sobrescrita para verbose_name encontrado na classe interna Meta do model.

verbose_name_plural

Uma sobrescrita para o verbose_name_plural encontrado na classe interna Meta do model.

Trabalhando com um model com duas ou mais chaves estrangeiras para o mesmo model pai

Algumas vezes é possível haver mais de uma chave estrangeira para o mesmo model. Vejamos esta instância de model:

class Friendship(models.Model):
    to_person = models.ForeignKey(Person, related_name="friends")
    from_person = models.ForeignKey(Person, related_name="from_friends")

Se você quiser mostrar um inline nas páginas adicionar/editar do admin para Person, você precisa explicitamente definir a chave primária, tendo em vista que ele não consegue definir automáticamente:

class FriendshipInline(admin.TabularInline):
    model = Friendship
    fk_name = "to_person"

class PersonAdmin(admin.ModelAdmin):
    inlines = [
        FriendshipInline,
    ]

Trabalhando com Models Intermediários Many-to-Many

Por padrão, os widgets do admin para relações muito-para-muitos serão mostrados inlines não importando qual model contém a referência atual para o ManyToManyField. No entanto, quando você especificar um model intermediário usando o argumento through para um ManyToManyField, o admin não mostrará o widget por padrão. Isso porque cada instância de model intermediário requer mais informações que poderiam ser mostradas num único widget, e o layout requerido por vários widgets irão variar dependendo do model intermediário.

No entanto, nós ainda queremos ter a possibilidade de editar estar informações inline. Felizmente, isso é fácil de fazer com admin models inline. Suponhamos que temos os seguintes models:

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

O primeiro passo em mostrar este model intermediário no admin é definir uma classe inline para o model Membership:

class MembershipInline(admin.TabularInline):
    model = Membership
    extra = 1

Este exemplo simples usa o valor padrão InlineModelAdmin para o model Membership, e limita os formulários adicionais para um. Isso poderia ser personalizado usando qualquer uma das opções disponíveis para classes InlineModelAdmin.

Agora crie visões no admin para os models Person e Group:

class PersonAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

class GroupAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

Finalmente, registre seus models Person e Group no site admin:

admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)

Agora seu site admin está configurado para editar objetos Membership tanto da página de detalhes do Person quanto do Group.

Usando relações genéricas como um inline

É possível usar um inline com objetos relacionados genericamente. Vamos dizer que você tenha os seguintes models:

class Image(models.Model):
    image = models.ImageField(upload_to="images")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey("content_type", "object_id")

class Product(models.Model):
    name = models.CharField(max_length=100)

Se você quer permitir a edição e criação de instâncias Image sobre Product você pode simplesmente usar GenericInlineModelAdmin fornecido pelo django.contrib.contenttypes.generic. No seu admin.py para esta aplicação de exemplo:

from django.contrib import admin
from django.contrib.contenttypes import generic

from myproject.myapp.models import Image, Product

class ImageInline(generic.GenericTabularInline):
    model = Image

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
    ]

admin.site.register(Product, ProductAdmin)

O django.contrib.contenttypes.generic fornece ambos um GenericTabularInline e GenericStackedInline e se comporta como qualquer outro inline. Veja a documentação do contenttypes para informações mais específicas.

Sobrescrevendo Templates do Admin

É relativamente fácil sobrescrever a maior parte dos templates que o módulo de admin usa para gerar as várias páginas de um site admin. Você pode sobrescrever somente algumas partes desses templates para uma app específica, ou um model específico.

Configurando os diretórios de template do admin do seu projeto

Os arquivos de template do admin estão localizados no diretório contrib/admin/templates/admin.

A fim de sobrescrever um ou mais deles, primeiro crie um diretório admin no diretórios de templates do seu projeto. Este pode ser qualquer um dos diretórios que você especificou no TEMPLATE_DIRS.

Dentro deste diretório admin, crie sub-diretórios com o nome de suas apps. Dentro destes sub-diretórios crie sub-diretórios com o nome de seus models. Perceba, que a aplicação admin procura por nomes de diretórios em minúsculo, então esteja certo do nome deles está todo em minúsculo, caso você esteja rodando sua aplicação num sistemas de arquivo case-sensitive.

Para sobrescrever um template do admin para uma app específica, copie e edite o template do diretório django/contrib/admin/templates/admin, e salve-o num dos diretórios criados a pouco.

Por exemplo, se nós procurarmos adicionar uma ferramenta na visão de listagem para todos os models de uma aplicação chamada my_app, nós copiariámos contrib/admin/templates/admin/change_list.html para o diretório templates/admin/my_app/ de seu projeto, e fariámos as mudanças necessárias.

Caso desejássemos adicionar uma ferramenta na visão de listagem somente para um model específico chamado ‘Page’, nós poderiámos copiar aquele mesmo arquivo para o diretório templates/admin/my_app/page de seu projeto.

Sobrescrever vs. substituir um template do admin

Por causa do design modular dos templates do admin, geralmente é necessário, mas nem sempre aconselhável, substituir todo um template. É quase semper melhor sobrescrever somente a seção do template que precisa ser mudada.

Para continuar o exemplo acima, nós queremos adicionar um novo link próximo ao History para o model Page. Depois de olhar no change_form.html nós determinamos que somente precisamos sobrescrever o bloco object-tools. Assim, aqui está o novo change_form.html :

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
  <ul class="object-tools">
    <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
    <li><a href="mylink/" class="historylink">My Link</a></li>
    {% if has_absolute_url %}
        <li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
            {% trans "View on site" %}</a>
        </li>
    {% endif%}
  </ul>
{% endif %}{% endif %}
{% endblock %}

E era isso! Se nós colocarmos este arquivo no diretório templates/admin/my_app, nosso link apareceria em todos os formulários de edição dos models.

Templates que podem ser sobrescritos por uma app ou model

Nem todo template em contrib/admin/templates/admin pode ser sobrescrito por app ou por model. Os seguintes podem:

  • change_form.html
  • change_list.html
  • delete_confirmation.html
  • object_history.html

Para a maioria dos templates que não são sobrescritos desta forma, você pode ainda sobrescrevê-los pra o seu projeto inteiro. É só colocar uma nova versão no seu diretório templates/admin. Este é particularmente útil para criar páginas de erro 404 e 500.

Note

Alguns dos templates do admin, como o change_list_request.html são usados para renderizar inclusion tags personalizadas. Estas podem ser sobrescritas, mas em alguns casos provavelmente é melhor você criar sua própria versão da tag em questão e dá-lhe um nome diferente. Desta forma você pode usá-la seletivamente.

Template raiz e de login

Se você deseja mudar o template index ou de login, seria melhor você criar sua própria instância de AdminSite (veja abaixo), e mudar as propriedades AdminSite.index_template ou AdminSite.login_template.

Objetos AdminSite

Um site de administração do Django é representado por uma instância do django.contrib.admin.sites.AdminSite; por padrão, uma instância desta classe é criada como django.contrib.admin.site e você pode registrar seus models e instâncias do modelAdmin nele.

Se você gostaria de configurar de setar sua própria interface de administração com comportamentos personalizados, contudo, você é livre para extender o AdminSite e sobrescrever ou adicionar qualquer coisa que queira. Então, simplesmente crie uma instância de sua classe extendida do AdminSite (da mesma forma como você instancia qualquer outra classe Python), e registre seus models e subclasses de ModelAdmin com ele ao invés de usar o padrão.

Atributos do AdminSite

AdminSite.index_template

Caminho para um template personalizado que será usado pela página principal do site de administração. Os templates podem sobrescrever ou extender os templates base do admin como descrito em Sobrescrevendo Templates do Admin.

AdminSite.login_template

Caminho para um templates personalizado que será usado pela página de login do site admin. Os templates podem sobrescrever ou extender os templates base do admin como descrito em Sobrescrevendo Templates do Admin.

Vinculando instâncias do AdminSite ao seu URLconf

O último passo ao configurar o admin do Django é vincular o sua instância AdminSite dentro do seu URLconf. Faça isso apontando uma certa URL para o método AdminSite.urls.

Neste exemplo, nós registramos a instância padrão AdminSite do django.contrib.admin.site na URL /admin

# urls.py
from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    ('^admin/(.*)', admin.site.root),
)

Acima nós usamos admin.autodiscover() para automaticamente carregar os módulos admin.py do INSTALLED_APPS.

Neste exemplo, nós registramos a instância do AdminSite myproject.admin.admin_site na URL /myadmin/

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import admin_site

urlpatterns = patterns('',
    ('^myadmin/(.*)', admin_site.root),
)

Realmente não há necessidade de usar o autodiscover quando estiver usando sua própria instância do AdminSite, tendo em vista que você provavelmente já tenha importado todos os seus módulos admin.py das aplicações no seu módulo myproject.admin.

Note que a expressão regular no URLpattern deve agrupar tudo que vier após a raiz da URL – por isso o (.*) nestes exemplos.

Vários sites admin no mesmo URLconf

É fácil criar várias instâncias de admin no mesmo site feito em Django. É só criar várias instâncias do AdminSite e colocá-los em URLs diferentes.

Neste exemplo, as URLs /baisc-admin/ e /advanced-admin/ realçam versões separadas do site admin – usando as instâncias do AdminSite myproject.admin.basic_site e myproject.admin.advanced_site, respectivamente:

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import basic_site, advanced_site

urlpatterns = patterns('',
    ('^basic-admin/(.*)', basic_site.root),
    ('^advanced-admin/(.*)', advanced_site.root),
)