Создание сайта на Django: Урок 42, создание системы рейтинга статей, часть 2 (JavaScript)
avatar
7 | (offline)
❤️‍🔥Notehunter Developer
Добавлено:
Категория: Руководства «Django»
Комментариев: 0

Для начала, изучите предыдущий урок: Создание сайта на Django: Урок 41, создание системы рейтинга статей, часть 1 (модель, представление)

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

modules/blog/urls.py

from django.urls import path, include

from modules.blog.models import Rating
from modules.blog.views import ArticleListView, ArticleDetailView, ArticleByCategoryListView, ArticleCreateView, \
    ArticleUpdateView, ArticleDeleteView, CommentCreateView, ArticleByTagListView, ArticleSearchResultView, \
    RatingCreateView

urlpatterns = [
    path('', ArticleListView.as_view(), name='home'),
    path('cat/<int:pk>/<str:slug>/', ArticleByCategoryListView.as_view(), name='article-by-cat'),
    path('articles/', include([
        path('', ArticleListView.as_view(), name='article-list'),
        path('create/', ArticleCreateView.as_view(), name='article-create-view'),
        path('tags/<str:tag>/', ArticleByTagListView.as_view(), name='article-list-by-tags'),
        path('<int:pk>/comments/create/', CommentCreateView.as_view(), name='comment-create-view'),
        path('<str:slug>/', ArticleDetailView.as_view(), name='article-detail'),
        path('<str:slug>/update/', ArticleUpdateView.as_view(), name='article-update-view'),
        path('<str:slug>/delete/', ArticleDeleteView.as_view(), name='article-delete-view'),
        path('<int:pk>/like/', RatingCreateView.as_view(value=Rating.LIKE), name='article-rating-like'),
        path('<int:pk>/dislike/', RatingCreateView.as_view(value=Rating.DISLIKE), name='article-rating-dislike'),
    ])),
    path('search/', ArticleSearchResultView.as_view(), name='search'),

]

Добавили мы именно:

  • path('<int:pk>/like/', RatingCreateView.as_view(value=Rating.LIKE), name='article-rating-like'),
  • path('<int:pk>/dislike/', RatingCreateView.as_view(value=Rating.DISLIKE), name='article-rating-dislike'),

Пояснения:

  • Мы передаем по определенной ссылке значение.

Теперь мы займемся JavaScript в файле article-list.js, его создадим по следующему пути:

templates/src/custom/js/article-list.js

ratingAll()

function ratingAll() {
    document.querySelectorAll('.btn-like, .btn-dislike').forEach((e) => {
    e.addEventListener('click', createRating)
})
}

function createRating(event) {
    event.preventDefault()
    const rating = this;
    const ratingId = rating.getAttribute('data-id');
    const ratingAction = rating.getAttribute('data-action');
    const ratingSum =  document.querySelector(`button[data-rating='${ratingId}']`);
    fetch(`/articles/${ratingId}/${ratingAction}/`, {
        method: 'POST',
        headers: {
            "X-CSRFToken": csrftoken,
            "X-Requested-With": "XMLHttpRequest",
        },
    }).then((response) => response.json()).then((result) => {
                if (result['error']) {
                    console.log(result['error'])
                } else {
                    ratingSum.innerHTML = `${result['get_rating_sum']}`
                }
        })
}

Пояснение: 

  • Инициализируем функцию.
  • Добавляем в кнопкам с классами .btn-like, .btn-dislike функцию по клику. На все кнопки на странице.
  • В самой функции createRating получаем из текущего передаваемого блока this атрибуты data-id, data-action. Data-id - id статьи. Data-action - это лайк, или дизлайк. 
  • Также передаем в кнопку с каждым id наше получаемое значение суммы рейтинга.
  • Используем csrftoken в headers. Мы его использовали в этом уроке: Создание сайта на Django: Урок 32, система древовидных комментариев: часть 2 (Добавление комментариев с помощью JavaScipt, оптимизация)
  • Далее данные преобразуем в json, получаем результат и выводим в консоль в случае ошибки, а если все успешно, то добавляем соотвествующий рейтинг в кнопку.

В самом шаблоне article-list.html не забываем добавить эти кнопки и подключить скрипт.

templates/modules/blog/articles/article-list.html

{% extends 'main.html' %}
{% load static %}
{% block content %}
    {% for article in articles %}
        <div class="card mb-3">
            <div class="row">
                <div class="col-md-4">
                    <figure class="mb-0">
                        <img src="{{ article.get_thumbnail }}" class="img-fluid h-100" alt="{{ article.title }}">
                    </figure>
                </div>
                <div class="col-md-8">
                    <div class="card-body">
                        <h4 class="card-title"><a href="{{ article.get_absolute_url }}">{{ article.title }}</a></h4>
                        <a class="card-subtitle" href="{% url 'article-by-cat' article.category.pk article.category.slug %}">#{{ article.category }}</a> / <time>{{ article.created_at }}</time>
                        <p class="card-text">
                            {{ article.short_description|safe }}
                        </p>
                        <div class="card-text">
                              <button class="btn shadow-sm btn-sm btn-success btn-like p-1" data-id="{{ article.pk }}" data-action="like" type="button">+1 </button>
                              <button class="btn shadow-sm btn-sm btn-danger btn-dislike p-1" data-id="{{ article.pk }}" data-action="dislike" type="button">-1 </button>
                              <button class="btn shadow-sm btn-sm btn-primary btn-sum-rating p-1" type="button" data-rating="{{ article.pk }}">{{ article.get_rating_sum }} </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    {% endfor %}
{% endblock %}

{% block script %}
    <script src="{% static 'custom/js/article-list.js' %}"></script>
{% endblock %}

Проверяем на сайте, нажимаем кнопки и все отлично работает. К этим кнопкам вы можете добавить иконки соответствующих реакций, чтобы это выглядело намного лучше.

Нам нужно ещё оптимизировать эту страницу. Переходим в менеджер статей:

modules/blog/managers/articles.py

from django.db import models


class ArticleManager(models.Manager):
    """
    Кастомный менеджер для модели статей.
    """

    def all(self):
        """
        Список статей (SQL запрос с фильтрацией для страницы списка статей)
        """
        return self.get_queryset().filter(is_published=True).select_related('category').prefetch_related('article_rating')

    def detail(self):
        """
        Детальная страница статьи с оптимизацией
        """
        return self.get_queryset().filter(is_published=True)\
            .select_related('category', 'updated_by', 'author', 'author__profile')\
            .prefetch_related('comments', 'comments__author', 'comments__author__profile')

Пояснение:

  • К методу def all() добавил .prefetch_related('article_rating')

Надеюсь у вас все получилось, на этом урок закончен.

Комментарии к статье 0
Комментариев нет
Форма добавления комментария (необходима регистрация)