Por Luferat em 06/11/2026
A página inicial lista todas as postagens ativas da entidade "post". Agora, queremos ver uma postagem única e completa quando clicamos nela.
Vamos aos passos:
Atualize blog/urls.py para adicionar a nova rota:
blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'), # Página inicial
path('contacts/', views.contacts, name='contacts'), # Página de contatos
path('post/<int:id>/', views.post_detail, name='post_detail'), # Página do post completo
]
Observe que a rota post/<int:id>/ espera um argumento id do tipo int. Assim:
Acessando /post/42/, a view recebe id=42.
Acessando /post/abc/, a rota não casa e o Django retorna Erro 404 automaticamente.
Crie a view: blog/views/post_detail.py com o conteúdo:
# blog/views/post_detail.py
from django.shortcuts import render, get_object_or_404
from ..models import Post
def post_detail(request, id):
post = get_object_or_404(
Post.objects.select_related('user'),
id=id,
is_active=True,
)
return render(
request,
'post_detail.html',
{'post': post}
)
Aqui, recebemos o id da postagem, na view (função) post_detail(request, id).
A variável post recebe a postagem completa, desde que is_active=True. Se o post não existe ou não atende aos requisitos, o Django mostra a página de Erro 404 (Not found).
Finalmente, passa o dicionário do contexto para render().
Para "ativar" essa view, adicione o import dela em blog/views/__init__.py que fica assim:
from .home import home
from .contacts import contacts
from .post_detail import post_detail # ← Adicione isso...
Crie o template blog/templates/post_detail.html:
# blog/templates/post_detail.html
{% extends '_base.html' %}
{% block content %}
<article>
{% if post.thumbnail %}
<div><img src="{{ post.thumbnail }}" alt="{{ post.title }}" class="w-100 rounded"></div>
{% endif %}
<h2 class="my-4">{{ post.title }}</h2>
<div class="alert alert-secondary p-2 text-end">
<small><em>
Por {{ post.user.get_full_name|default:post.user.username }}
em {{ post.created_at|date:"d/m/Y \à\s H:i" }}.
</em></small>
</div>
<div>{{ post.textbody|safe }}</div>
</article>
{% endblock %}
{% block aside %}
<aside>
<h5>{{ post.user.get_full_name|default:post.user.username }}</h5>
<p><small>Membro desde {{ post.user.date_joined|date:"d/m/Y" }}</small></p>
</aside>
{% endblock %}
Todos os dados deste post são recebidos no template, na variável post. Assim, por exemplo, {{ post.title }} mostra o título deste post.
Observe que também recebemos os dados do usuário, proprietário do post. Observe o trecho:
{{ post.user.get_full_name|default:post.user.username }}
Isso mostra o username do proprietário, por padrão. Se o proprietário tem first_name e last_name preenchidos esse dados são exibidos em vez do username, por get_full_name.
Já os códigos |date: ... são filtros que formatam as datas.
Edite o link para cada postagem:
Abra blog/templates/home.html e localize:
<a href="#{{ post.id }}">Ver post</a>
Troque para:
<a href="{% url 'post_detail' id=post.id %}">Ver post</a>
{% url 'post_detail' id=post.id %} gera o link dinamicamente ({% url ... %}) e adiciona o id do post, gerando algo como post/10/.
Salve tudo, verifique se o servidor do aplicativo está rodando e faça os testes em http://localhost:8000...