---
title: "Escrevendo sua primeira app Django, parte 3"
version: 3.0
locale: pt-br
source: https://docs.djangoproject.com/pt-br/3.0/intro/tutorial03/
canonical: https://djangodocs.dev/pt-br/3.0/intro/tutorial03/
---
# Escrevendo sua primeira app Django, parte 3

Este tutorial inicia-se onde o Tutorial 2 terminou. Vamos continuar a aplicação web de enquete e focaremos na criação da interface pública – “views”.

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

## Visão Geral

Uma view é um “tipo” de página Web em sua aplicação Django que em geral serve a uma função específica e tem um template específico. Por exemplo, em uma aplicação de blog, você deve ter as seguintes views:

- Página inicial do blog - exibe os artigos mais recentes.
- Página de “detalhes” - página de vínculo estático permanente para um único artigo.
- Página de arquivo por ano - exibe todos os meses com artigos para um determinado ano.
- Página de arquivo por mês - exibe todos os dias com artigos para um determinado mês.
- Página de arquivo por dia - exibe todos os artigos de um determinado dia.
- Ação de comentários - controla o envio de comentários para um artigo.

Em nossa aplicação de enquetes, nós teremos as seguintes views:

- Página de “índice” de enquetes - exibe as enquetes mais recente.
- Question “detail” page – displays a question text, with no results but
  with a form to vote.
- Página de “resultados” de perguntas - exibe os resultados de uma pergunta em particular.
- Ação de voto - gerencia a votação para uma escolha particular em uma enquete em particular.

In Django, web pages and other content are delivered by views. Each view is
represented by a Python function (or method, in the case of class-based views).
Django will choose a view by examining the URL that’s requested (to be precise,
the part of the URL after the domain name).

Now in your time on the web you may have come across such beauties as
`ME2/Sites/dirmod.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B`.
You will be pleased to know that Django allows us much more elegant
*URL patterns* than that.

A URL pattern is the general form of a URL - for example:
`/newsarchive/<year>/<month>/`.

To get from a URL to a view, Django uses what are known as ‘URLconfs’. A
URLconf maps URL patterns to views.

This tutorial provides basic instruction in the use of URLconfs, and you can
refer to [Despachante de URL](/pt-br/3.0/topics/http/urls/) for more information.

## Escrevendo mais views

Agora vamos adicionar mais algumas views em `polls/views.py`. Estas views são um pouco diferentes, porque elas recebem um argumento:

*polls/views.py*

```python
def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)
```

Wire these new views into the `polls.urls` module by adding the following
[`path()`](/pt-br/3.0/ref/urls/#django.urls.path) calls:

*polls/urls.py*

```python
from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

Dê uma olhada no seu navegador, em `/polls/34/`. Ele vai executar o método `detail()` e mostrar o ID que você informou na URL. Tente “/polls/34/results/” e “/polls/34/vote/” também – Eles vão mostrar a pagina resultadoss e a pagina de votação.

Quando alguém requisita uma página do seu site Web – vamos dizer “/polls/34/”, o Django irá carregar o módulo Python `mysite.urls` para o qual ele aponta devido a configuração em [`ROOT_URLCONF`](/pt-br/3.0/ref/settings/#std-setting-ROOT_URLCONF). Ele encontra a variável nominada `urlpatterns` e atravessa as descrições na mesma ordem. Depois de encontrar a combinação `'polls/'`, ele reparte o texto encontrado (`"polls/"`) e envia o restante – `"34/"` – para o URLconf ‘polls.urls’ para processamento posterior. Lá ele encontra `'<int:question_id>/'`, resultando em uma chamada para a view `detail()` como abaixo:

```
detail(request=<HttpRequest object>, question_id=34)
```

A parte `question_id=34` vem de `<int:question_id>`. Usando símbolos de “menor” e “maior” ele “captura” parte da URL e envia como um argumento de palavra-chave para a função view. A parte `:question_id>` da string define o nome que será usado para identificar a descrição a ser encontrada, e a parte `<int:` é um conversor que determina qual descrição deve ser usada para encontrar essa parte do caminho da  URL.

There’s no need to add URL cruft such as `.html` – unless you want to, in
which case you can do something like this:

```
path('polls/latest.html', views.index),
```

Mas, não o faça isso, Isto é idiota.

## Escreva views que façam algo

Cada view é responsável por fazer uma das duas coisas: devolver um objeto [`HttpResponse`](/pt-br/3.0/ref/request-response/#django.http.HttpResponse) contendo o conteúdo para a página requisitada, ou levantar uma exceção como [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404). O resto é com você.

Sua view pode ler registros do banco de dados, ou não. Ela pode usar um sistema de templates como o do Django - ou outro sistema de templates Python de terceiros - ou não. Ele pode gerar um arquivo PDF, saída em um XML, criar um arquivo ZIP sob demanda, qualquer coisa que você quiser,usando qualquer biblioteca Python você quiser.

Tudo que o Django espera é que a view devolva um [`HttpResponse`](/pt-br/3.0/ref/request-response/#django.http.HttpResponse). Ou uma exceção.

Porque é conveniente, vamos usar a própria API de banco de dados do Django, a qual cobrimos em [Tutorial 2](/pt-br/3.0/intro/tutorial02/). Aqui uma nova tentativa de view  `index()`, a qual mostra as últimas 5 “poll questions” do sistema, separada por vírgulas, de acordo com sua data de publicação:

*polls/views.py*

```python
from django.http import HttpResponse

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged
```

Há um problema aqui, no entanto: o design da página esta codificado na view. Se você quiser mudar a forma de apresentação de sua página, você terá de editar este código diretamente em  Python. Então vamos usar o sistema de templates do Django para separar o design do código Python:

Primeiro, crie um diretório chamado \`\` templates\`\` em seu diretório `polls`. O Django irá procurar templates lá.

A sua configuração de projeto [`TEMPLATES`](/pt-br/3.0/ref/settings/#std-setting-TEMPLATES) descreve como o Django vai carregar e renderizar templates. O arquivo de configuração padrão usa o backend `DjangoTemplates` do qual a opção [`APP_DIRS`](/pt-br/3.0/ref/settings/#std-setting-TEMPLATES-APP_DIRS)  é configurada como `True`. Por convenção `DjangoTemplates` procura por um subdiretório “templates” em cada uma das [`INSTALLED_APPS`](/pt-br/3.0/ref/settings/#std-setting-INSTALLED_APPS).

Within the `templates` directory you have just created, create another
directory called `polls`, and within that create a file called
`index.html`. In other words, your template should be at
`polls/templates/polls/index.html`. Because of how the `app_directories`
template loader works as described above, you can refer to this template within
Django as `polls/index.html`.

> **Namespacing  de template**
>
> Now we *might* be able to get away with putting our templates directly in
> `polls/templates` (rather than creating another `polls` subdirectory),
> but it would actually be a bad idea. Django will choose the first template
> it finds whose name matches, and if you had a template with the same name
> in a *different* application, Django would be unable to distinguish between
> them. We need to be able to point Django at the right one, and the best
> way to ensure this is by *namespacing* them. That is, by putting those
> templates inside *another* directory named for the application itself.

Ponha o seguinte código neste template:

*polls/templates/polls/index.html*

```html+django
{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}
```

> **Note**
>
> To make the tutorial shorter, all template examples use incomplete HTML. In
> your own projects you should use [complete HTML documents](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document).

Agora vamos atualizar nossa view `index` em `polls/views.py` para usar o template:

*polls/views.py*

```python
from django.http import HttpResponse
from django.template import loader

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))
```

Esse código carrega o template chamado `polls/index.html` e passa um contexto para ele. O contexto é um dicionário mapeando nomes de variáveis ​​para objetos Python.

Carregue a página apontando seu navegador para “/polls/”, e você deve ver uma lista contendo a questão “What’s up” do  [Tutorial 2](/pt-br/3.0/intro/tutorial02/). O link aponta para página de detalhes das perguntas.

### Um atalho: [`render()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.render)

É um estilo muito comum carregar um template, preenchê-lo com um contexto e retornar um objeto [`HttpResponse`](/pt-br/3.0/ref/request-response/#django.http.HttpResponse) com o resultado do template renderizado. O Django fornece este atalho. Aqui esta toda a view `index()` reescrita:

*polls/views.py*

```python
from django.shortcuts import render

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)
```

Note que uma vez que você tiver feito isto em todas as views, nós não vamos mais precisar importar [`loader`](/pt-br/3.0/topics/templates/#module-django.template.loader) e [`HttpResponse`](/pt-br/3.0/ref/request-response/#django.http.HttpResponse) (você vai querer manter `HttpResponse` se você ainda tiver os métodos criados para `detail`, `results`, e `vote`).

A função [`render()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.render) recebe o nome do template como primeiro argumento e um dicionário opcional como segundo argumento. Ele retorna um objeto [`HttpResponse`](/pt-br/3.0/ref/request-response/#django.http.HttpResponse) do template informado renderizado com o contexto determinado.

## Levantando um erro 404

Agora, vamos abordar a view de detalhe de pergunta – a página que mostra as questões para uma enquete lançada. Aqui esta a view:

*polls/views.py*

```python
from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})
```

Um novo conceito aqui: A view levanta uma exceção [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404) se a enquete com ID requisitado não existir.

Nós iremos discutir o que você poderia colocar no template `polls/detail.html` mais tarde, mas se você gostaria de ter o exemplo acima funcionando rapidamente, um arquivo contendo:

*polls/templates/polls/detail.html*

```html+django
{{ question }}
```

irá ajudar a começar por enquanto.

### Um atalho: [`get_object_or_404()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.get_object_or_404)

É um estilo muito comum usar `get()` e levantar uma exceção [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404) se o objeto não existir. O Django fornece um atalho para isso. Aqui esta a view `detail()`, reescrita:

*polls/views.py*

```python
from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

A função [`get_object_or_404()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.get_object_or_404) recebe um modelo do Django como primeiro argumento e uma quantidade arbitrária de argumentos nomeados, que ele passa para a função do módulo `get()`. E levanta uma exceção [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404) se o objeto não existir.

> **Filosofia**
>
> Porquê usamos uma função auxiliar [`get_object_or_404()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.get_object_or_404) ao invés de automaticamente capturar as exceções [`ObjectDoesNotExist`](/pt-br/3.0/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) em alto nível ou fazer a API do modelo levantar [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404) ao invés de    [`ObjectDoesNotExist`](/pt-br/3.0/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist)?
>
> Porque isso seria acoplar a camada de modelo com a camada de visão. Um dos   principais objetivo do design do Django é manter o baixo acoplamento. Alguns acoplamento controlado é introduzido no módulo [`django.shortcuts`](/pt-br/3.0/topics/http/shortcuts/#module-django.shortcuts).

Existe também a função [`get_list_or_404()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.get_list_or_404), que trabalha da mesma forma que [`get_object_or_404()`](/pt-br/3.0/topics/http/shortcuts/#django.shortcuts.get_object_or_404) – com a diferença de que ela usa `filter()` ao invés de `get()`. Ela levanta [`Http404`](/pt-br/3.0/topics/http/views/#django.http.Http404) se a lista estiver vazia.

## Use o sistema de template

De volta para a view `detail()` da nossa aplicação de enquentes. Dada a variável de contexto `question`, aqui está como o template `polls/detail.htm` deve ser:

*polls/templates/polls/detail.html*

```html+django
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
```

O sistema de templates usa uma sintaxe separada por pontos para acessar os atributos da variável. No exemplo de `{{ question.question_text }}`, primeiro o Django procura por dicionário no objeto `question`. Se isto falhar, ele tenta procurar por um atributo – que funciona, neste caso. Se a procura do atributo também falhar, ele irá tentar uma chamada do tipo list-index.

A chamada do método acontece no laço [`{% for %}`](/pt-br/3.0/ref/templates/builtins/#std-templatetag-for): `poll.choice_set.all` é interpretado como código Python `poll.choice_set.all()`, que retorna objetos `Choice` iteráveis que são suportado para ser usado na tag `{% for %}`.

Veja o [guia de templates](/pt-br/3.0/topics/templates/) para maiores detalhes sobre templates.

## Removendo URLs codificados nos templates

Lembre-se, quando escrevemos o link para uma pergunta no template `polls/templates/index.html`, o link foi parcialmente codificado como este:

```html+django
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
```

O problema com com essa abordagem acoplada, hardcoded é que torna muito difícil alterar URLs em projetos com muitos templates. Todavia, se definimos o argumento name nas funções [`path()`](/pt-br/3.0/ref/urls/#django.urls.path) no módulo `polls.urls`, você pode remover a dependência de um caminho de URL específico nas configurações de url usando a template tag `{% url %}`:

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

A maneira como isso funciona é, observando as definições de  URL como especificado no módulo `polls.urls`. Você pode ver exatamente onde o nome de URL ‘detalhe’ é definido a seguir

```
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
```

Se você quiser alterar a URL das views de detalhe da enquete para outra coisa, talvez para algo como `polls/specifics/12/` em vez de fazê-lo no template (ou templates) você mudaria em `polls/urls.py`:

```
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
```

## Namespacing nomes de URL

Este projeto tutorial tem apenas um aplicação, `polls`. Em projetos reais Django, pode haver cinco, dez, vinte ou mais aplicações. Como o Django diferencia os nomes de URL entre eles? Por exemplo, a aplicação `polls` tem uma view `detail`, e assim pode um aplicativo no mesmo projeto que é para um blog. Como é que faz para que o Django saiba qual view da aplicação será criada para a url ao usar a tag de template\`\` {% url%} ?

A resposta é adicionar namespaces a seu URLconf. No arquivo `polls/urls.py`, continue e adicione um `app_name`  para configurar o namespace da aplicação.

*polls/urls.py*

```python
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/results/', views.results, name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

Agora mudo seu template\`\`polls/index.html\`\` de:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

para apontar para a view de detalhes d namespace:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
```

When you’re comfortable with writing views, read [part 4 of this tutorial](/pt-br/3.0/intro/tutorial04/) to learn the basics about form processing and generic
views.
