Теперь, когда теги реализованы, с ними можно многое делать. С их помощью легко классифицировать посты. Материалы на схожие темы будут содержать общие теги. Создадим функциональность, которая будет отображать похожие посты, отталкиваясь от количества одинаковых тегов. Так, когда пользователь прочтет один материал, ему можно будет порекомендовать другой, связанный с ним тематически.
Для получения похожих постов нужно совершить следующие шаги:
- Получить все теги текущего поста.
- Получить все посты, к которым проставлены любые из этих же тегов.
- Исключить текущий материал, чтобы не рекомендовать его же.
- Отсортировать результаты по количеству общих тегов с текущим постом.
- Если тегов два или более, рекомендовать самый последний.
- Ограничить количество рекомендуемых постов.
Эти шаги превращаются в сложный QuerySet, который будет включать представление post_detail
. Откройте файл views.py
приложения блога и добавьте следующий импорт в верхней его части:
from django.db.models import Count
Это функция агрегации Count
из ORM Django. Она позволяет осуществлять совокупный подсчет тегов. django.db.models
включает следующие функции агрегации:
Avg
: среднее значениеMax
: максимальное значениеMin
: минимальное значениеCount
: подсчет объектов
Узнать больше об агрегации можно здесь: https://docs.djangoproject.com/en/2.0/topics/db/aggregation/.
Добавьте следующие строки в представление post_detail
перед функцией render()
со следующим уровнем отступа:
# Список похожих постов
post_tags_ids = post.tags.values_list('id', flat=True)
similar_posts = Post.published.filter(tags__in=post_tags_ids) \
.exclude(id=post.id)
similar_posts = similar_posts.annotate(same_tags=Count('tags')) \
.order_by('-same_tags', '-publish')[:4]
Этот код выполняет следующее:
- Получаем список Python с ID тегов текущего поста. QuerySet
values_list()
возвращает кортеж со значениями для заданных полей. Передаемflat=True
, чтобы получить список в формате[1, 2, 3, ...]
. - Получаем все посты с одним из этих тегов, не включая текущий.
- Используем функцию агрегации
Count
для генерации поляsame_tags
, которое содержит количество общих тегов. - Сортируем результаты по количество общих тегов (в порядке убывания) по
publish
, чтобы отображать последние [по дате публикации] посты в числе первых, если у нескольких одинаковое количество общих тегов. Обрезаем результаты, чтобы получить только первые четыре поста.
Добавьте объект similar_posts
в словарь контекста для функции render()
:
return render(request,
'blog/post/detail.html',
{'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form,
'similar_posts': similar_posts})
Теперь нужно отредактировать шаблон blog/post/detail.html
и добавить следующий код перед списком комментариев к посту:
<h2>Similar posts</h2>
{% for post in similar_posts %}
<p>
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</p>
{% empty %}
There are no similar posts yet.
{% endfor %}
Теперь страница поста должна выглядеть так:
Теперь можно рекомендовать похожие посты пользователям. django-taggit
также включает менеджер similar_objects()
, который можно использовать для получения постов с общими тегами. Посмотреть на все менеджеры django-taggit
можно здесь: https://django-taggit.readthedocs.io/en/latest/api.html.
Также можно добавить список тегов на страницу поста по принципу шаблона blog/post/list.html
.