Aula 15 – Levantando um erro 404

More videos
   

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.

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'),
]

Para baixar o código como está até agora, acesse o meu github no link abaixo:
https://github.com/toticavalcanti/django_course/tree/views

AULA  14

AULA  16

Todas as Aulas da App Polls

Página Principal

Com isso finalizamos a parte 03 do tutorial.

Obrigado

Até a próxima

Category: App Polls, Django
About The Author
-

5 Comentários

  • Antonio Carlos
    Reply

    tanto fazendo assim:
    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})
    Quanto assim:
    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})
    Não aparece a mensagem de erro personalizada, aparece assim para mim:
    Page not found (404)
    Request Method: GET
    Request URL: http://127.0.0.1:8000/polls/2/
    Raised by: polls.views.detail
    Using the URLconf defined in curso.urls, Django tried these URL patterns, in this order:

    1. polls/ [name=’index’]
    2. polls/ / [name=’detail’]
    The current path, polls/2/, matched the last one.

    • toticavalcanti
      Reply

      Opa Antonio Carlos, blz?
      O erro não diz muita coisa esclarecedora, tá dizendo que não achou a página, que foi lançado no polls.views.detail usando a definição feita em curso.urls.
      Ele tá procurando nessa ordem:
      1. polls/ [name=’index’]
      2. polls/ / [name=’detail’]
      The current path, polls/2/, matched the last one.

      Tá informando no final que polls/2/ tá batendo com a última 2. polls/ / [name=’detail’], mas tem uma coisa estranha, que é a barra espaço barra, polls/ /.
      Só não sei te dizer exatamente o que tá ocorrendo, mas acho que tem alguma coisa errada nas rotas.
      Qualquer coisa, se você não conseguir solucionar, baixa o código do meu github da forma como ele tá nessa aula, acho que é a branch views, no post tem o link.
      \o/ A.C. 😉

  • Antonio Carlos
    Reply

    Olá!
    Essa parte não sei pq não apareceu todo o texto:
    2. polls/ / [name=’detail’] na verdade aparece assim ‘polls/ / [name=’detail’]’

    segue meus arquivos url
    do polls:
    “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’),
    ]”

    agora o outro:
    “from django.contrib import admin
    from django.urls import include, path

    urlpatterns = [
    path(‘polls/’, include(‘polls.urls’)),
    path(‘admin/’, admin.site.urls),
    ]”

    Abs

    • toticavalcanti
      Reply

      Fala Antonio Carlos, agora que vi, acho que você colocou uma barra a mais nessa parte:
      path(‘/results/’, views.results, name=’results’),
      path(‘/vote/’, views.vote, name=’vote’),

      Tirando a barra a mais, vai ficar assim:
      path(‘results/’, views.results, name=’results’),
      path(‘vote/’, views.vote, name=’vote’),

      Tenta aí, 😉
      \o/

  • Antonio Carlos
    Reply

    não sei pq aqui não aparece texto entre os sinais de maior e menor

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>