Разработка представлений списка и детальной информации
Представления блога
View блога будут простыми функциями (позже переделаем на классы). blog/views.py:
from django.shortcuts import get_object_or_404, render
from .models import Post
def post_list(request):
posts = Post.published.all()
return render(request, "blog/post/list.html", {"posts": posts})
def post_detail(request, id):
post = get_object_or_404(Post, id=id, status=Post.Status.PUBLISHED)
return render(request, "blog/post/detail.html", {"post": post})
Почему фильтр по статусу и в detail
Если искать пост просто по id, любой, кто угадает номер, прочитает черновик. Поэтому ищем только среди опубликованных. Можно короче — передать менеджер:
post = get_object_or_404(Post.published, id=id)
Без get_object_or_404
Для понимания — то же самое вручную:
from django.http import Http404
def post_detail(request, id):
try:
post = Post.published.get(id=id)
except Post.DoesNotExist:
raise Http404("Пост не найден")
return render(request, "blog/post/detail.html", {"post": post})
Маршруты
Создайте blog/urls.py:
from django.urls import path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.post_list, name="post_list"),
path("<int:id>/", views.post_detail, name="post_detail"),
]
Подключите в mysite/urls.py:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("blog/", include("blog.urls", namespace="blog")),
]
Пространство имён blog позволяет ссылаться на маршруты как blog:post_list и blog:post_detail, не боясь конфликтов с другими приложениями.
Канонический URL поста
Добавим в модель метод, возвращающий адрес поста:
from django.urls import reverse
class Post(models.Model):
...
def get_absolute_url(self):
return reverse("blog:post_detail", args=[self.id])
Теперь в шаблонах можно писать {{ post.get_absolute_url }}, а в админке появится кнопка «Смотреть на сайте». В уроке «Работа с URL» мы заменим адрес по id на красивый адрес с датой и слагом — и благодаря get_absolute_url ничего, кроме этого метода и маршрута, менять не придётся.
Проверим
Шаблонов ещё нет, поэтому /blog/ пока выдаст ошибку TemplateDoesNotExist — это нормально. Займёмся шаблонами в следующем уроке.
Итог
post_list—Post.published.all(),post_detail—get_object_or_404среди опубликованных.- Маршруты приложения с
app_name = "blog"подключаются черезinclude(). get_absolute_url()— единое место, где определяется адрес поста.
Практика решено 0 из 5
Напишите view post_list, которая получает все опубликованные посты через менеджер published
и рендерит blog/post/list.html с переменной posts.
from django.shortcuts import render
from .models import Post
def post_list(request):
posts = Post.published.all()
return render(request, "blog/post/list.html", {"posts": posts})
Напишите view post_detail(request, id), которая находит опубликованный пост по id
(иначе 404) и рендерит blog/post/detail.html с переменной post.
from django.shortcuts import get_object_or_404, render
from .models import Post
def post_detail(request, id):
post = get_object_or_404(Post, id=id, status=Post.Status.PUBLISHED)
return render(request, "blog/post/detail.html", {"post": post})
Напишите blog/urls.py: пространство имён blog, маршрут "" → post_list (имя post_list)
и "<int:id>/" → post_detail (имя post_detail).
from django.urls import path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.post_list, name="post_list"),
path("<int:id>/", views.post_detail, name="post_detail"),
]
Какой адрес у списка постов, если в mysite/urls.py написано path("blog/", include("blog.urls", namespace="blog"))?
Что увидит пользователь, открыв адрес черновика /blog/5/?
Войдите, чтобы отмечать пройденные уроки.