В этом разделе мы рассмотрим создание системы Лайк / Дизлайк в Django без перезагрузки страницы с помощью JavaScript.
Создание модели рейтинга
Первым делом мы создадим модель рейтинга, для этого в файле models.py приложения blog добавим код модели:
class Rating(models.Model):
"""
Модель рейтинга: Лайк - Дизлайк
"""
post = models.ForeignKey(to=Post, verbose_name='Запись', on_delete=models.CASCADE, related_name='ratings')
user = models.ForeignKey(to=User, verbose_name='Пользователь', on_delete=models.CASCADE, blank=True, null=True)
value = models.IntegerField(verbose_name='Значение', choices=[(1, 'Нравится'), (-1, 'Не нравится')])
time_create = models.DateTimeField(verbose_name='Время добавления', auto_now_add=True)
ip_address = models.GenericIPAddressField(verbose_name='IP Адрес')
class Meta:
unique_together = ('post', 'ip_address')
ordering = ('-time_create',)
indexes = [models.Index(fields=['-time_create', 'value'])]
verbose_name = 'Рейтинг'
verbose_name_plural = 'Рейтинги'
def __str__(self):
return self.post.title
Этот код определяет модель Rating, которая наследуется от models.Model из Django. Модель содержит следующие поля:
post- поле внешнего ключа, которое ссылается на модельPost.user- поле внешнего ключа, которое ссылается на модельUser. Оно может быть пустым, так мы планируем разрешить гостям ставить лайк и дизлайк.value- поле выбора значений, которое может иметь одно из двух значений:1(Нравится) или-1(Не нравится).time_create- поле даты и времени, которое устанавливается автоматически при создании объекта.ip_address- поле IP-адреса.
Модель определяет несколько метаданных для управления ее поведением:
unique_togetherгарантирует уникальность комбинацииpostиip_address.orderingуказывает порядок сортировки по умолчанию.indexesопределяет индекс на поляtime_createиvalue.verbose_nameиverbose_name_pluralопределяют отображаемые имена модели в административном интерфейсе.
Не забываем провести миграции:
python manage.py makemigrations
python manage.py migrate
Подсчет рейтинга у записи
Теперь нам необходимо написать функцию подсчета суммы рейтинга, для этого у модели Post добавим следующий метод:
class Post(models.Model):
# поля и методы модели
def get_sum_rating(self):
return sum([rating.value for rating in self.ratings.all()])
Создаем представление для работы с рейтингом
Нам необходимо создать представление, которое будет работать с JS, для этого в нашем файле views.py приложения blog добавим следующее представление:
from django.http import JsonResponse
from django.views.generic import View
from .models import Rating
class RatingCreateView(View):
model = Rating
def post(self, request, *args, **kwargs):
post_id = request.POST.get('post_id')
value = int(request.POST.get('value'))
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
ip = x_forwarded_for.split(',')[0] if x_forwarded_for else request.META.get('REMOTE_ADDR')
ip_address = ip
user = request.user if request.user.is_authenticated else None
rating, created = self.model.objects.get_or_create(
post_id=post_id,
ip_address=ip_address,
defaults={'value': value, 'user': user},
)
if not created:
if rating.value == value:
rating.delete()
return JsonResponse({'status': 'deleted', 'rating_sum': rating.post.get_sum_rating()})
else:
rating.value = value
rating.user = user
rating.save()
return JsonResponse({'status': 'updated', 'rating_sum': rating.post.get_sum_rating()})
return JsonResponse({'status': 'created', 'rating_sum': rating.post.get_sum_rating()})
Этот код представляет класс-представление, который обрабатывает POST- запросы на создание и изменение модели Rating. Он использует стандартный метод post() для обработки запроса.
post_id = request.POST.get('post_id')
value = int(request.POST.get('value'))
При получении запроса, представление извлекает данные из запроса, включая идентификатор статьи, значение оценки, IP-адрес клиента и аутентифицированного пользователя (если таковой имеется).
Затем используется метод get_or_create() для получения экземпляра модели Rating. Если объект уже существует, он либо удаляется, либо обновляется соответствующим образом, а если объект новый, он сохраняется.
Наконец, метод возвращает JsonResponse, содержащий статус операции (created, updated или deleted) и сумму оценок для записи, полученных с помощью метода get_sum_rating(), определенного в модели Post.
Добавим нашу модель в админ панель, для этого в файл admin.py приложения blog добавим следующий код:
from .models import Rating
@admin.register(Rating)
class RatingAdmin(admin.ModelAdmin):
"""
Админ-панель модели рейтинга
"""
pass
В следующем шаге мы добавим маршруты и JS-скрип обработчика этой системы.