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

This tutorial begins where [Tutorial 2](/pt-br/6.1/intro/tutorial02/) left off.
We’re continuing the web-poll application and will focus on creating the public
interface – “views.”

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

## Visão Geral

A view is a “type” of web page in your Django application that generally serves
a specific function and has a specific template. For example, in a blog
application, you might have the following 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/6.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/6.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"),
]
```

Take a look in your browser, at “/polls/34/”. It’ll run the `detail()`
function and display whatever ID you provide in the URL. Try
“/polls/34/results/” and “/polls/34/vote/” too – these will display the
placeholder results and voting pages.

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/6.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:

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

A parte `question_id=34` vem de `<int:question_id>`. O uso de colchetes angulares “captura” parte da URL e a envia como um argumento de palavra-chave para a função de view. A parte `question_id` da string define o nome que será usado para identificar o padrão correspondente, e a parte `int` é um conversor que determina quais padrões devem corresponder a essa parte do caminho da URL. Os dois pontos (`:`) separam o conversor e o nome do padrão.

## Escreva views que façam algo

Cada view é responsável por fazer uma das duas coisas: devolver um objeto [`HttpResponse`](/pt-br/6.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/6.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 devolva um [`HttpResponse`](/pt-br/6.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/6.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
```

There’s a problem here, though: the page’s design is hardcoded in the view. If
you want to change the way the page looks, you’ll have to edit this Python
code. So let’s use Django’s template system to separate the design from Python
by creating a template that the view can use.

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/6.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/6.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/6.1/ref/settings/#std-setting-INSTALLED_APPS).

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

> **Namespacing  de template**
>
> Agora nós *podemos* ser capazes de colocar nossos templates diretamente em `polls/templates` (ao invés de criar outro subdiretório `polls`), mas na verdade seria uma má ideia. O Django irá escolher o primeiro template que encontrar cujo nome corresponda, e se você tivesse um template com o mesmo nome em uma aplicação *diferente*, o Django não conseguiria distinguir entre eles. Precisamos ser capazes de apontar o Django para o caminho certo, e a melhor maneira de garantir isso é *namespacing* neles. Ou seja, colocando esses modelos dentro de *outro* diretório nomeado para o próprio aplicativo.

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**
>
> Para tornar o tutorial mais curto, todos os exemplos de modelo usam HTML incompleto. Em seus próprios projetos você deve usar documentos HTML completos.

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

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

É um estilo muito comum usar `get()` e levantar uma exceção [`Http404`](/pt-br/6.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/6.1/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/6.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/6.1/topics/http/shortcuts/#django.shortcuts.get_object_or_404) ao invés de automaticamente capturar as exceções [`ObjectDoesNotExist`](/pt-br/6.1/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) em alto nível ou fazer a API do modelo levantar [`Http404`](/pt-br/6.1/topics/http/views/#django.http.Http404) ao invés de    [`ObjectDoesNotExist`](/pt-br/6.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. Algum acoplamento controlado é introduzido no módulo [`django.shortcuts`](/pt-br/6.1/topics/http/shortcuts/#module-django.shortcuts).

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

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