# documentação Django 2.0.8

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

    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()` calls:

polls/urls.py

    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` 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` contendo o conteúdo para a página requisitada, ou levantar uma exceção como `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`. Ou uma exceção.

Porque é conveniente, vamos usar a própria API de banco de dados do Django, a qual cobrimos em Tutorial 2. 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

    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` 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` é configurada como `True`. Por convenção DjangoTemplates` procura por um subdiretório “templates” em cada uma das `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

    {% 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

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

### Um atalho: `render()`

É um estilo muito comum carregar um template, preenchê-lo com um contexto e retornar um objeto `HttpResponse` com o resultado do template renderizado. O Django fornece este atalho. Aqui esta toda a view `index()` reescrita:

polls/views.py

    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` e `HttpResponse` (você vai querer manter `HttpResponse` se você ainda tiver os métodos criados para `detail`, `results`, e `vote`).

A função `render()` recebe o nome do template como primeiro argumento e um dicionário opcional como segundo argumento. Ele retorna um objeto `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

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

    {{ question }}

irá ajudar a começar por enquanto.

### Um atalho: `get_object_or_404()`

É um estilo muito comum usar `get()` e levantar uma exceção `Http404` se o objeto não existir. O Django fornece um atalho para isso. Aqui esta a view `detail()`, reescrita:

polls/views.py

    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()` 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` se o objeto não existir.

Filosofia

Porquê usamos uma função auxiliar `get_object_or_404()` ao invés de automaticamente capturar as exceções `ObjectDoesNotExist` em alto nível ou fazer a API do modelo levantar `Http404` ao invés de `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`.

Existe também a função `get_list_or_404()`, que trabalhada da mesma forma que `get_object_or_404()` – com a diferença de que ela usa `filter()` ao invés de `get()`. Ela levanta `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

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

    <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()` 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:

    <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

    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

    <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

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