Django База [2023]: Представление на основе классов: DetailView, детальная статья #8
Django

Django База [2023]: Представление на основе классов: DetailView, детальная статья #8

Razilator

В данной статье мы рассмотрим ещё одно представление в Django 4.1, по которому мы будем получать одну статью по заданному полю slug, которое мы добавили в модель Article.

В прошлом уроке мы рассмотрели представление ListView для вывода статей на главной странице.

Представление на основе класса: DetailView

Это представление для получения одного объекта из набора QuerySet, получаемое по slug или же pk, не исключаются любые другие поля.

Давайте создадим данное представление в нашем приложении блог, в файле views.py, выложу полный файл с добавление нового кода

blog/views.py
from django.views.generic import ListView, DetailView

from .models import Article


class ArticleListView(ListView):
    model = Article
    template_name = 'blog/articles_list.html'
    context_object_name = 'articles'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Главная страница'
        return context


class ArticleDetailView(DetailView):
    model = Article
    template_name = 'blog/articles_detail.html'
    context_object_name = 'article'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = self.object.title
        return context

Пояснения:

  • model - наша модель статьи
  • template_name - название нашего кастомного шаблона
  • context_object_name - представленная переменная в шаблоне
  • context['title] - наш заголовок передаваемый в
  • self.object.title - это наш объект, т.е наша статья, у которой мы получаем заголовок.

Добавление представления в urls.py

Теперь нам необходимо добавить обработку по ссылке в urls.py нашего приложения.

blog/urls.py
from django.urls import path

from .views import ArticleListView, ArticleDetailView

urlpatterns = [
    path('', ArticleListView.as_view(), name='home'),
    path('articles/<str:slug>/', ArticleDetailView.as_view(), name='articles_detail'),
]

Добавление метода get_absolute_url в модель Article

Теперь нам нужно внести изменения в модель Article, добавив новую функцию:

blog/models.py
from django.db import models
from django.core.validators import FileExtensionValidator
from django.contrib.auth import get_user_model
from django.urls import reverse

from mptt.models import MPTTModel, TreeForeignKey


class Article(models.Model):
    """
    Модель постов для сайта
    """    

    STATUS_OPTIONS = (
        ('published', 'Опубликовано'), 
        ('draft', 'Черновик')
    )

    title = models.CharField(verbose_name='Заголовок', max_length=255)
    slug = models.CharField(verbose_name='Альт.название', max_length=255, blank=True, unique=True)
    # Другие поля...
    
    # Другие функции...
    
    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('articles_detail', kwargs={'slug': self.slug})    

Пояснения:

  • Данный метод позволяет получать прямую ссылку на статью, без вызова {% url '' %}
  • Также мы импортировали reverse для формирования правильной ссылки.

Примечание:

  • Если вы столкнулись с проблемой при сохранении поста в админ-панеле, а именно, у вас нет slug, или он одинаков, не беспокойтесь, в следующем уроке про slug мы рассмотрим решение.

Изменение шаблонов, добавление шаблона articles_detail.html

Для просмотра детальной статьи, мы из списка статей должны получать ссылку на полную новость, давайте проведем изменения в articles_list.html добавив ссылку на полную статью

templates/blog/articles_list.html
{% extends 'main.html' %}

{% block content %}
    {% for article in articles %}
        <img src={{ article.thumbnail.url }} alt={{ article.title }} width="150"/>
        <strong>{{ article.title }}</strong>
        <p>{{ article.short_description }}</p>
        <small>{{ article.time_create }}</small>
        <hr>
        <span>{{ article.category.title }}</span>
        <hr>
        <a href="{{ article.get_absolute_url }}">Подробнее</a>
    {% endfor %}
{% endblock %}

Отлично, теперь создадим шаблон полной статьи: templates/blog/articles_detail.html

templates/blog/articles_detail.html
{% extends 'main.html' %}

{% block content %}
        <img src={{ article.thumbnail.url }} alt={{ article.title }} width="250"/>
        <strong>{{ article.title }}</strong>
        <p>{{ article.full_description }}</p>
        <small>{{ article.time_create }}</small>
        <hr>
        <span>{{ article.category.title }}</span>
{% endblock %}

Примечание: в DetailView нам не нужен цикл, поэтому напрямую обращаемся к article, это переменная, которую мы задали в context_object_name = 'article'.

Давайте запустим наш проект и проверим, получилось ли у нас все как надо:

Ссылка подробнее из метода get_absolute_url
Ссылка подробнее из метода get_absolute_url

Как видим, ссылка правильная. Перейдем на страницу статьи:

Детальная статья
Детальная статья

Отлично, у нас все получилось! Более подробно вы можете изучить DetailView в документации Django

;