Criando uma primeira aplicação com Django e mysql
Levantando um erro 404
Agora, vamos abordar a view detail da Question – a página que mostra as questões para uma enquete lançada.
Aqui está a view detail () reescrita:
/mysite/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.
Vamos fazer inicialmente um template bem simples só para funcionar rapidamente, coloque no arquivo polls/templates/polls/detail.html apenas:
{{ question }}
Isso 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:
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().
Se o objeto não existir ele levanta uma exceção
Http404
Filosofia
Porque usar a função auxiliar
get_object_or_404() ao invés de capturar as exceções
ObjectDoesNotExist em alto nível ou fazer a
API do modelo levantar
Http404 ao invés de
ObjectDoesNotExist?
Porque isso acoplaria a camada de modelo com a camada de visão.
Um dos principais objetivo do design do Django é manter o baixo acoplamento.
Alguns acoplamentos controlados são introduzidos 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.
Use o sistema de template
De volta para a view
detail().
Dada a variável de contexto question, aqui está como o template polls/detail.htm deve ficar:
polls/templates/polls/detail.html
<!-- Pega o texto da question e coloca no h1 -->
<h1>{{ question.question_text }}</h1>
<!-- Cria uma lista-->
<ul>
<!-- Para cada choice acossiada a question -->
{% for choice in question.choice_set.all %}
<!-- Pega o texto de cada choice associada a essa question e põe na lista -->
<li>{{ choice.choice_text }}</li>
{% endfor %}<!-- Fim do for -->
</ul><!-- Fim da lista -->
O sistema de templates usa uma sintaxe separada por pontos para acessar os atributos da variável.
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>
O problema com esta abordagem, muita acoplada é que ele se torna um desafio para mudar
URLs em projetos com um monte de templates.
No entanto, uma vez que você definiu o argumento nome na
url() no módulo
polls.urls, você pode remover uma dependência de caminhos de
URL específicos definidos em suas configurações de
URL usando a tag de template ''
{% url%} '':
<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.
A URL ' detail' é definido a seguir:
...
# O valor 'name' é chamado pelo {% url %} template tag
path('/', 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:
...
# adicione a palavra 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
NAMESPACING
Nesse projeto da mysite, temos apenas uma aplicação, a 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 uma outra app no mesmo projeto que é para um blog, também tem uma view.detail.
Como é que faz para que o Django saiba qual view da app 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.
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('/', views.detail, name='detail'),
path('/results/', views.results, name='results'),
path('/vote/', views.vote, name='vote'),
]
Com isso finalizamos a parte 03 do tutorial.
Obrigado
Até a próxima