Как добавить кнопку Like/Dislike
S0mebodyВ этом мини-руководстве мы добавим в наш блог функцию Like/Dislike.
В качестве примечания, мы реализуем эту функцию при использовании вьюшек на основе классов для нашего BlogPost DetailView.
Давайте начнем, во-первых, в нашем models.py нам нужно добавить в нашу модель BlogPost следующие поля:
# models.py
class BlogPost(models.Model):
...
likes = models.ManyToManyField(User, related_name='blogpost_like')
def number_of_likes(self):
return self.likes.count()
likes - это отношение «многие ко многим» с нашей моделью пользователя, означающее, что пользователи (объекты) могут иметь несколько лайков, а сообщения в блоге могут иметь несколько лайков. Функция number_of_likes вернет количество лайков для текущего объекта сообщения в блоге.
После каждого изменения в файле models.py нам нужно открыть наш терминал и выполнить миграции в нашу базу данных:
>> python manage.py makemigrations >> python manage.py migrate
Давайте теперь создадим нашу вьюшку для нашей кнопки Like. В файле view.py прямо перед (или после) классом BlogPost DetailView определите функцию BlogPostLike:
# views.py
from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
def BlogPostLike(request, pk):
post = get_object_or_404(BlogPost, id=request.POST.get('blogpost_id'))
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return HttpResponseRedirect(reverse('blogpost-detail', args=[str(pk)]))
blogpost_id будет нашим идентификатором кнопки в нашем blogpost_detail.html. Каждый раз, когда вошедший в систему пользователь нажимает кнопку Like, мы извлекаем его id, а затем проверяем, понравился ли этот пользователь уже или нет текущий пост в блоге. Затем мы перенаправим пользователя на ту же страницу блога (например, обновление этой страницы).
ПРИМЕЧАНИЕ. К сожалению, мы не можем избежать обновления страницы после каждого нажатия кнопки Like/Dislike. Чтобы пропустить обновление, необходимо реализовать всю функциональность кнопки Like/Dislike внутри HTML-кода с подробным описанием блога, используя Ajax.js. В этом мини-руководстве не рассматривается этот тип реализации.
Теперь это тот же файл view.py, в котором мы реализовали наш BlogPost DetailView, нам нужно добавить в наш get_context_data следующее:
# views.py
class BlogPostDetailView(DetailView):
model = BlogPost
# template_name = MainApp/BlogPost_detail.html
# context_object_name = 'object'
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
likes_connected = get_object_or_404(BlogPost, id=self.kwargs['pk'])
liked = False
if likes_connected.likes.filter(id=self.request.user.id).exists():
liked = True
data['number_of_likes'] = likes_connected.number_of_likes()
data['post_is_liked'] = liked
return data
В нашей функции get_context_data мы получим текущий первичный ключ записи блога и проверим, понравился ли данный пост в блоге текущему авторизованному пользователю. Мы сохраним этот оператор в локальной переменной, чтобы отправить его в качестве контекста в наш блогpost_detail на основе HTML. Мы также получим количество лайков (вызывая ранее написанную функцию), чтобы отобразить количество лайков непосредственно в нашем HTML-шаблоне.
Давайте также добавим это новое представление на основе функций в наш urls.py:
# urls.py
from django.urls import path
from .views import (
...
BlogPostLike,
...
)
urlpatterns = [
...
path('blogpost-like/<int:pk>', views.BlogPostLike, name="blogpost_like"),
...
]
Наконец, в наш blogpost_detail.html напишем следующее:
<!-- LIKES -->
{% if user.is_authenticated %}
<form action="{% url 'blogpost_like' object.id %}" method="POST">
{% csrf_token %}
{% if post_is_liked %}
<button type="submit" name="blogpost_id" value="{{object.id}}" class="btn btn-info">Unlike</button>
{% else %}
<button type="submit" name="blogpost_id" value="{{object.id}}" class="btn btn-info">Like</button>
{% endif %}
</form>
{% else %}
<a class="btn btn-outline-info" href="{% url 'login' %}?next={{request.path}}">Log in to like this article!</a><br>
{% endif %}
<strong class="text-secondary">{{ number_of_likes }} Like{{ number_of_likes|pluralize }}</strong>
Готово!

