Aula 15 – Levantando um erro 404

Criando uma primeira aplicação com Django e mysql

Levantando um erro 404

https://docs.djangoproject.com/pt-br/1.11/intro/tutorial03/

Levantando um erro 404

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.

/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
url(r'^(?P<question_id>[0-9]+)/$', 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'
url(r'^specifics/(?P<question_id>[0-9]+)/$', 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.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

Mude seu template ‘polls/templates/polls/index.html’ que deve está assim:

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

Para:

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

Agora a modificação para usar o namespace polls (‘polls:detail’), apontando para a view de detalhes do namespace, ficando da seguinte forma:

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

Com isso finalizamos a parte 03 do tutorial.

Obrigado

Até a próxima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *