sexta-feira, 16 de março de 2018

Tutorial 5 de 10

Codificando uma app simples

Levantando um erro 404:

Vamos editar o arquivo votacao/views.py:
A View de detalhe de pergunta que é a página que mostra as questões para uma enquete lançada. Codifique:
...
from django.http import Http404
...
def detail(request, questao_id):
    try:
        questao = Questao.objects.get(pk=questao_id)
    except Questao.DoesNotExist:
        raise Http404("Questão não existe!")
    return render(request, 'votacao/detail.html', {'questao': questao})
...

A view levanta uma exceção Http404 se a enquete com ID requisitado não existir.
Agora, crie o arquivo votacao/templates/votacao/detail.html.
Depois codifique:
{{ questao }}

Veja o resultado de 2 testes, exibindo a questão (/votacao/2/, e outro exibindo o erro levantado (/votacao/3/):



É comum usar get() e levantar uma exceção Http404 se o objeto não existir. O Django fornece um atalho para isso. Veja o código de votacao/views.py:

from django.shortcuts import get_object_or_404
...
def detail(request, questao_id):
    questao = get_object_or_404(Questao, pk=questao_id)
    return render(request, 'votacao/detail.html', {'questao': questao})
...

A função get_object_or_404() recebe um model do Django como 1º 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.

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 view. Um dos principais objetivos do design do Django é manter o baixo acoplamento. Alguns acoplamentos controlados é introduzido no módulo django.shortcuts.
Existe também a função get_list_or_404(), que trabalha 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. Veja o erro apresentado na tela, com o mesmo exemplo acima:

--------------------------------------------------------------------
Melhorando a template detail.html.
Codifique:

<h1>{{ questao.texto_questao }}</h1>
<ul>
{% for escolha in questao.escolha_set.all %}
    <li>{{ escolha }}</li>
{% endfor %}
</ul>

O sistema de templates usa uma sintaxe separada por pontos para acessar os atributos da variável. 
No exemplo de {{ questao.texto_questao }}, 1º o Django procura por dicionário no objeto questao. Se isto falhar, ele tenta procurar por um atributo (que funciona, neste caso). Se a procura do atributo também falhar, irá tentar uma chamada do tipo list-index.
--------------------------------------------------------------------
A chamada do método acontece no laço {% for %}: o que estiver dentro deste bloco é interpretado como código Python. O questao.escolha_set.all(), retorna objetos Escolha iteráveis que são suportados para ser usado na tag {% for %}.
--------------------------------------------------------------------
Removendo URLs codificados nos templates:
Quando escrevemos o link para uma pergunta no template votacao/templates/index.html, o link foi parcialmente codificado como este:
<li><a href="/votacao/{{ questao.id }}/">
{{ questao.texto_questao }}</a></li>

O problema de se fazer desta forma é que mudar URLs em projetos com muitos templates se torna bem desafiador. 

Todavia, depois que definiu o nome do argumento na função path() em votacao/urls, você pode remover uma dependência de paths de URLs específicos definidos nas configurações de URL usando a template tag {% url %}:



<li><a href="{% url 'detail' questao.id %}">

{{ questao.texto_questao }}</a></li>
--------------------------------------------------------------------
A maneira como isso funciona é, observando as definições de URL como especificado em votacao.urls. Você pode ver exatamente onde o nome de URL 'detail' é definido a seguir:

# o valor de 'name' como chamado por {% url %} template tag:
path('<int:questao_id>/', views.detail, name='detail'),
--------------------------------------------------------------------
Se você quiser alterar a URL das views de 'detail' da enquete para outra coisa, exemplo: votacao/specifics/12/ em vez de fazê-lo nos templates, mude apenas em votacao/urls.py:

# adicionando a palavra 'specifics':
path('specifics/<int:questao_id>/', views.detail, name='detail'),
--------------------------------------------------------------------
Namespacing nomes de URL:

Este tutorial trata apenas de uma aplicação, votacao. Em projetos reais, Django, pode haver 5, 10 ou mais aplicações. 
Como o Django diferencia os nomes de URL entre eles? 
Por exemplo, a aplicação votacao tem uma view 'detail', mas poderíamos ter um aplicativo no mesmo projeto com este mesmo nome de view. 
Como o Django sabe qual view da aplicação será criada para a url ao usar a tag de template {% url%}?
Resposta: adicionar namespaces a seu URLconf. No arquivo votacao/urls.py, adicione um app_name para configurar o namespace da aplicação. Insira o código:
...
app_name = 'votacao'
...

Em seguida, mude o template votacao/index.html:
De:
<li><a href="{% url 'detail' questao.id %}">
{{ questao.texto_questao }}</a></li>

Para:
<li><a href="{% url 'votacao:detail' questao.id %}">
{{ questao.texto_questao }}</a></li>
--------------------------------------------------------------------

Nenhum comentário:

Postar um comentário

Tutorial 10 de 10

Codificando uma app simples Continuando a alteração no admin... Personalizando a listagem da página de Administração: Vamos fazer melh...