---
title: "Escrevendo seu primeiro app Django, parte 7"
version: 6.1
locale: pt-br
source: https://docs.djangoproject.com/pt-br/6.1/intro/tutorial07/
canonical: https://djangodocs.dev/pt-br/6.1/intro/tutorial07/
---
# Escrevendo seu primeiro app Django, parte 7

This tutorial begins where [Tutorial 6](/pt-br/6.1/intro/tutorial06/) left off.
We’re continuing the web-poll application and will focus on customizing
Django’s automatically-generated admin site that we first explored in
[Tutorial 2](/pt-br/6.1/intro/tutorial02/).

> **Onde obter ajuda:**
>
> Se tiver problemas enquanto caminha por este tutorial, por favor consulte a seção [Obtendo ajuda](/pt-br/6.1/faq/help/) da FAQ.

## Personalize o formulário do site de administração

Ao registrarmos o modelo de ```Question``através da linha ``admin.site.register(Question)```, o Django constrói um formulário padrão para representá-lo. Comumente, você desejará personalizar a apresentação e o funcionamento dos formulários do site de administração do Django. Para isto, você precisará informar ao Django as opções que você quer utilizar ao registrar o seu modelo.

Vamos ver como isto funciona reordenando os campos no formulário de edição. Substitua a linha àdmin.site.register(Question)\` por:

*`polls/admin.py`*

```python
from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fields = ["pub_date", "question_text"]

admin.site.register(Question, QuestionAdmin)
```

Você seguirá este padrão – crie uma classe de “model admin”, em seguida, passe-a como o segundo argumento para o `admin.site.register()` – todas as vezes que precisar alterar as opções administrativas para um modelo.

Essa mudança específica no código acima faz com que a “Publication date” apareça antes do campo “Question”:

![Fields have been reordered](intro/_images/admin07.png)

Isso não é impressionante com apenas dois campos, mas para formulários com dúzias deles, escolher uma ordem intuitiva é um detalhe importante para a usabilidade.

E por falar em dúzias de campos, você pode querer dividir o formulário em grupos:

*`polls/admin.py`*

```python
from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Date information", {"fields": ["pub_date"]}),
    ]

admin.site.register(Question, QuestionAdmin)
```

O primeiro elemento de cada tupla em [`fieldsets`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets) é o título do grupo. Aqui está como o nosso formulário se parece agora:

![Form has fieldsets now](intro/_images/admin08t.png)

## Adicionando objetos relacionados

Ok, nós temos nossa página de administração Questão, mas a `Questão` tem múltiplas `Questõe`s, e a página de administração não exibe escolhas.

Ainda.

There are two ways to solve this problem. The first is to register `Choice`
with the admin just as we did with `Question`:

*`polls/admin.py`*

```python
from django.contrib import admin

from .models import Choice, Question

# ...
admin.site.register(Choice)
```

Agora “Choices” é uma opção disponível no site de administração do Django. O formulário de “Add choice” se parece com isto:

![Choice admin page](intro/_images/admin09.png)

Nesse formulário, o campo “Question” é uma caixa de seleção contendo todas as enquetes no banco de dados. O Django sabe que uma [`ForeignKey`](/pt-br/6.1/ref/models/fields/#django.db.models.ForeignKey) deve ser representada no site de administração como um campo `<select>`. No nosso caso, só existe uma enquete até agora.

Also note the “Add another question” button (displayed as a plus sign) to the
right of the “Question” field. Every `ForeignKey` relationship gets this
button for free. When you click this button, you’ll get a popup window with the
“Add question” form. If you add a question in that window and click “Save”,
Django will save the question to the database and dynamically add it as the
selected choice on the “Add choice” form you’re looking at.

Mas, sério, essa é uma maneira ineficiente de adicionar objetos `Choice` ao sistema. Seria muito melhor se você pudesse adicionar várias opções diretamente quando criasse um objeto `Question`. Vamos fazer isso acontecer.

Remova a chamada `register()` do modelo `Choice`. Então edite o código de registro de `Question` para que fique assim:

*`polls/admin.py`*

```python
from django.contrib import admin

from .models import Choice, Question

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Date information", {"fields": ["pub_date"], "classes": ["collapse"]}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)
```

Isso informa ao Django: Objetos “`Choice` são editados na mesma página de administração de `Question`. Por padrão, forneça campos suficientes para 3 escolhas.”

Carregue a página “Add question” para ver como está:

![Add question page now has choices on it](intro/_images/admin10t.png)

Funciona assim: há três blocos para Escolhas relacionadas – como especificado em `extra` –, mas a cada vez que você retorna à página de “Alteração” para um objeto já criado, você ganha outros três blocos extra.

At the end of the three current slots you will find an “Add another Choice”
link. If you click on it, a new slot will be added. If you want to remove the
added slot, you can click on the X to the top right of the added slot. This
image shows an added slot:

![Additional slot added dynamically](intro/_images/admin14t.png)

One small problem, though. It takes a lot of screen space to display all the
fields for entering related `Choice` objects. For that reason, Django offers
a tabular way of displaying inline related objects. To use it, change the
`ChoiceInline` declaration to read:

*`polls/admin.py`*

```python
class ChoiceInline(admin.TabularInline): ...
```

Com o `TabularInline` (em vez de `StackedInline`), os objetos relacionados são exibidos de uma maneira mais compacta, formatada em tabela:

![Add question page now has more compact choices](intro/_images/admin11t.png)

Note that there is an extra “Delete?” column that allows removing rows added
using the “Add another Choice” button and rows that have already been saved.

## Personalize a listagem da página de administração

Agora que a página de administração de Pergunta está bonita, vamos fazer algumas melhorias à página “change list” – aquela que exibe todas as enquetes do sistema.

Aqui é como ela está até agora:

![Polls change list page](intro/_images/admin04t.png)

By default, Django displays the `str()` of each object. But sometimes it’d be
more helpful if we could display individual fields. To do that, use the
[`list_display`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display) admin option, which is a
list of field names to display, as columns, on the change list page for the
object:

*`polls/admin.py`*

```python
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date"]
```

For good measure, let’s also include the `was_published_recently()` method
from [Tutorial 2](/pt-br/6.1/intro/tutorial02/):

*`polls/admin.py`*

```python
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date", "was_published_recently"]
```

Agora a página de edição de enquetes está assim:

![Polls change list page, updated](intro/_images/admin12t.png)

Você pode clicar no cabeçalho da coluna para ordená-las por estes valores – exceto no caso do `was_published_recently`, porque a ordenação pelo resultado de um método arbitrário não é suportada. Também note que o cabeçalho da coluna
para `was_published_recently` é, por padrão, o nome do método (com underscores substituídos por espaços), e que cada linha contem a representação da saída.

You can improve that by using the [`display()`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.display)
decorator on that method (extending the `polls/models.py` file that was
created in [Tutorial 2](/pt-br/6.1/intro/tutorial02/)), as follows:

*`polls/models.py`*

```python
from django.contrib import admin

class Question(models.Model):
    # ...
    @admin.display(
        boolean=True,
        ordering="pub_date",
        description="Published recently?",
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
```

For more information on the properties configurable via the decorator, see
[`list_display`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display).

Edite o arquivo `polls/admin.py` de novo e adicione uma melhoria à  página de lista de edição `Question`: Um filtro usando [`list_filter`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter). Adicione a seguinte linha ao `QuestionAdmin`:

```
list_filter = ["pub_date"]
```

Isso adiciona uma barra lateral “Filter” que permite às pessoas filtrarem a lista de edição pelo campo `pub_date`:

![Polls change list page, updated](intro/_images/admin13t.png)

O tipo do filtro apresentado depende do tipo do campo pelo qual você está filtrando. Como `pub_date` é uma instância da classe  [`DateTimeField`](/pt-br/6.1/ref/models/fields/#django.db.models.DateTimeField), o Django consegue deduzir que os filtros apropriados são: “Qualquer data”, “Hoje”, “Últimos 7 dias”, “Esse mês”, “Esse ano”.

Isso está ficando bom. Vamos adicionar capacidade de pesquisa:

```
search_fields = ["question_text"]
```

Isso adiciona um campo de pesquisa ao topo da lista de edição. Quando alguém informa termos de pesquisa, o Django irá pesquisar o campo `question_text`. Você pode usar quantos campos quiser – entretanto, por ele usar uma consulta `LIKE` internamente, limitar o número de campos de pesquisa a um número razoável, será mais fácil para o seu banco de dados para fazer pesquisas.

Now’s also a good time to note that change lists give you free pagination. The
default is to display 100 items per page.

> **See also**
>
> The following [`ModelAdmin`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin) options allow
> further customization of change lists:
> [`list_per_page`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_per_page),
> [`search_fields`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields),
> [`date_hierarchy`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.date_hierarchy), and
> [`list_display`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display).

## Personalize a aparência do site de administração

Obviamente, ter “Django administration” no topo de cada página de administração é ridículo. Isso é só um texto de exemplo.

You can change it, though, using Django’s template system. The Django admin is
powered by Django itself, and its interfaces use Django’s own template system.

### Personalize os templates do seu *projeto*

Create a `templates` directory in your `djangotutorial` directory.
Templates can live anywhere on your filesystem that Django can access. (Django
runs as whatever user your server runs.) However, keeping your templates within
the project is a good convention to follow.

Abra seu arquivo de configurações (`mysite/settings.py`, lembre-se) e adicione uma opção  [`DIRS`](/pt-br/6.1/ref/settings/#std-setting-TEMPLATES-DIRS). na configuração [`TEMPLATES`](/pt-br/6.1/ref/settings/#std-setting-TEMPLATES) setting:

*`mysite/settings.py`*

```python
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]
```

[`DIRS`](/pt-br/6.1/ref/settings/#std-setting-TEMPLATES-DIRS) é uma lista de diretórios de arquivos que serão checados quando o Django carregar seus templates, ou seja, caminhos de busca.

> **Organizando templates**
>
> Just like the static files, we *could* have all our templates together, in
> one big templates directory, and it would work perfectly well. However,
> templates that belong to a particular application should be placed in that
> application’s template directory (e.g. `polls/templates`) rather than the
> project’s (`templates`). We’ll discuss in more detail in the
> [reusable apps tutorial](/pt-br/6.1/intro/reusable-apps/) *why* we do this.

Now create a directory called `admin` inside `templates`, and copy the
template `admin/base_site.html` from within the default Django admin
template directory in the source code of Django itself
([django/contrib/admin/templates](https://github.com/django/django/blob/stable/6.1.x/django/contrib/admin/templates)) into that directory.

> **Onde estão os arquivos de código-fonte do Django?**
>
> Se você tiver dificuldade em encontrar onde os arquivos do Django estão localizados em seu sistema, execute o seguinte comando:
>
> ```console
> $ python -c "import django; print(django.__path__)"
> ```
>
> *Windows*
>
> ```doscon
> ...\> py -c "import django; print(django.__path__)"
> ```

Então, edite o arquivo e substitua `{{ site_header|default:_('Django administration') }}` (incluindo as chaves) com nome do seu próprio site como desejar. Você deve acabar com uma secção de código como:

```html+django
{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></div>
{% if user.is_anonymous %}
  {% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
```

Nós usamos esta abordagem para ensinar-lhe como substituir templates. Em um projeto real, você provavelmente usaria o atributo [`django.contrib.admin.AdminSite.site_header`](/pt-br/6.1/ref/contrib/admin/#django.contrib.admin.AdminSite.site_header) para fazer mais facilmente essa personalização em particular.

Esse template contém uma série de textos como `{% block branding %}` e `{{ tittle }}`. As tags `{%` e `{{` fazem pate da linguagem de templates do Django. Quando o Django renderiza o template “admin/base\_site.html”, o seu conteúdo é processado por essa linguagem de templates para produzir a página HTML final, assim como vimos no [Tutorial 3](/pt-br/6.1/intro/tutorial03/).

Note que qualquer template padrão do site de administração pode ser sobrescrito. Para sobrescrever um template, apenas faça a mesma coisa que você fez com `base_site.html` – copie ele do diretório padrão para o seu próprio diretório, e faça as mudanças.

### Personalize os templates da sua *aplicação*

Leitores astutos irão se perguntar: Mas se [`DIRS`](/pt-br/6.1/ref/settings/#std-setting-TEMPLATES-DIRS) estava vazio por padrão, como o Django pôde encontrar o diretório padrão dos templates do site de administração? A resposta é, Desde que [`APP_DIRS`](/pt-br/6.1/ref/settings/#std-setting-TEMPLATES-APP_DIRS) seja `True`, o Django irá automaticamente procurar por um subdiretório `templates/` dentro de cada pacote de aplicação, para usar como fallback(Não esqueça que `django.contrib.admin` é uma aplicação)

Nossa aplicação de enquetes não é muito complexa e não precisa de templates personalizados para o site de administração. Mas se ele crescer e ficar mais sofisticado e necessária a modificação dos templates padrão de administração do Django para algumas de suas funcionalidades, seria mais sensato  modificar os templates da *aplicação*, e não os do *projeto*. Dessa forma, você poderia incluir a aplicação de enquete em qualquer novo projeto e ter a certeza que iria encontrar os templates personalizados que você precisa.

Veja a [documentação de carga de template](/pt-br/6.1/ref/templates/api/#template-loaders) \- para mais informação sobre como o Django acha seus templates.

## Personalize a página inicial do site de administração

De maneira similar, você pode querer personalizar a aparência da página inicial do site de administração do Django.

Por padrão, ele exibe todas as aplicações em [`INSTALLED_APPS`](/pt-br/6.1/ref/settings/#std-setting-INSTALLED_APPS), que estão registrados na aplicação de administração, em ordem alfabética. E você pode querer fazer alterações significativas no layout. Além do que, a página inicial é provavelmente a página mais importante da página de administração, e deve ser fácil de usar.

The template to customize is `admin/index.html`. (Do the same as with
`admin/base_site.html` in the previous section – copy it from the default
directory to your custom template directory). Edit the file, and you’ll see it
uses a template variable called `app_list`. That variable contains every
installed Django app. Instead of using that, you can hardcode links to
object-specific admin pages in whatever way you think is best.

When you’re comfortable with the admin, read [part 8 of this
tutorial](/pt-br/6.1/intro/tutorial08/) to learn how to use third-party packages.
