Criando uma primeira aplicação com Django e mysql
Levantando um erro 404
https://docs.djangoproject.com/pt-br/1.11/intro/tutorial03/
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.
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.
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. 😉
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
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/
não sei pq aqui não aparece texto entre os sinais de maior e menor