---
title: "Escrevendo sua primeira app Django, parte 3"
version: 2.1
locale: pt-br
source: https://docs.djangoproject.com/pt-br/2.1/intro/tutorial03/
canonical: https://djangodocs.dev/pt-br/2.1/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”.

## 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.

No Django, páginas web e outros conteúdos são entregues por views. Cada view é representada por uma simples função Python(ou metodos, no caso das class-based views). O django irá escolher uma view examinando a URL que foi requisitada (para ser preciso, a parte da URL depois do nome de dominio).

Agora em seu tempo pela internet você deve ter visto coisas lindas como “ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”. Você ficará satisfeito em saber que o Django permite *padrões de URL* muito mais elegantes do que isso.

Um padrão de URL é simplesmente a forma geral de uma URL - por exemplo: `/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/2.1/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/2.1/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.

When somebody requests a page from your website – say, “/polls/34/”, Django
will load the `mysite.urls` Python module because it’s pointed to by the
[`ROOT_URLCONF`](/pt-br/2.1/ref/settings/#std-setting-ROOT_URLCONF) setting. It finds the variable named `urlpatterns`
and traverses the patterns in order. After finding the match at `'polls/'`,
it strips off the matching text (`"polls/"`) and sends the remaining text –
`"34/"` – to the ‘polls.urls’ URLconf for further processing. There it
matches `'<int:question_id>/'`, resulting in a call to the `detail()` view
like so:

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

The `question_id=34` part comes from `<int:question_id>`. Using angle
brackets “captures” part of the URL and sends it as a keyword argument to the
view function. The `:question_id>` part of the string defines the name that
will be used to identify the matched pattern, and the `<int:` part is a
converter that determines what patterns should match this part of the URL path.

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: retornar um objeto [`HttpResponse`](/pt-br/2.1/ref/request-response/#django.http.HttpResponse) contendo o conteúdo para a página requisitada, ou levantar uma exceção como [`Http404`](/pt-br/2.1/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 retorne um [`HttpResponse`](/pt-br/2.1/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/2.1/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/2.1/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/2.1/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/2.1/ref/settings/#std-setting-INSTALLED_APPS).

Dentro do diretório `templates` que acabou de criar, crie outro diretório `polls`, e dentro crie um arquivo chamado `index.html`. Em outras palavras, seu template deve estar em `polls/templates/polls/index.html`. Devido a forma como o carregador de templates `app_directories` funciona como descrito acima, você pode referenciar este template dentro do Django simplesmente como `polls/index.html`.

> **Namespacing  de template**
>
> Agora nós *podemos* ser capazes de avnçar com a colocação dos nossos modelos diretamente em `polls/templates` (em vez de criar outro `subdiretório poll`), mas na verdade seria uma má ideia. Django irá escolher o primeiro template que encontra cujo nome corresponde, e se você tivesse um template com o mesmo nome em uma aplicação *diferente*, O Django e incapaz de distinguir entre eles. Precisamos ser capazes de apontar Django no caminho certo, e a maneira mais fácil de garantir isso é usar *namespacing*. Ou seja, colocando esses templates dentro de *outro* diretório nomeado para a aplicação em si.

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 %}
```

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/2.1/intro/tutorial02/). O link aponta para página de detalhes das perguntas.

### Um atalho: [`render()`](/pt-br/2.1/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/2.1/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/2.1/topics/templates/#module-django.template.loader) e [`HttpResponse`](/pt-br/2.1/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/2.1/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/2.1/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/2.1/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/2.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404)

É um estilo muito comum usar `get()` e levantar uma exceção [`Http404`](/pt-br/2.1/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/2.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404) recebe um modelo do Django como primeiro argumento e um número arbitrário de argumentos chave, que ele passa para a função do módulo `get()`. E levanta uma exceção [`Http404`](/pt-br/2.1/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/2.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404) ao invés de automaticamente capturar as exceções [`ObjectDoesNotExist`](/pt-br/2.1/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) em alto nível ou fazer a API do modelo levantar [`Http404`](/pt-br/2.1/topics/http/views/#django.http.Http404) ao invés de    [`ObjectDoesNotExist`](/pt-br/2.1/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/2.1/topics/http/shortcuts/#module-django.shortcuts).

Existe também a função [`get_list_or_404()`](/pt-br/2.1/topics/http/shortcuts/#django.shortcuts.get_list_or_404), que trabalhada da mesma forma que [`get_object_or_404()`](/pt-br/2.1/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/2.1/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/2.1/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/2.1/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>
```

The problem with this hardcoded, tightly-coupled approach is that it becomes
challenging to change URLs on projects with a lot of templates. However, since
you defined the name argument in the [`path()`](/pt-br/2.1/ref/urls/#django.urls.path) functions in
the `polls.urls` module, you can remove a reliance on specific URL paths
defined in your url configurations by using the `{% url %}` template tag:

```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>
```

Quando você estiver confortável em escrever views, leia a parte 4 deste tutorial para aprender sobre processamento de formulários simples e sobre as views genéricas.
