- Get all the tags of the current post.
- Get all the posts with any of the same tags.
- Exclude the current post to avoid recommending the same post.
- Sort the results by the number of common tags with the current post.
- If there are two or more tags, recommend the most recent one.
- Limit the number of recommended posts.
These steps turn into a complex QuerySet, which will include the post_detail
view. Open the views.py
file of the blog application and add the following import at the top of it:
from django.db.models import Count
This is a Count
aggregation function from Django’s ORM. It allows for aggregate counting of tags. django.db.models
includes the following aggregation functions:
Avg
: average valueMax
: maximal valueMin
: minimum valueCount
: object count
Learn more about aggregation here: https://docs.djangoproject.com/en/2.0/topics/db/aggregation/. Add the following lines to the post_detail
view before render()
with the following indentation level:
# List of similar posts
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]
This code does the following:
- Get a Python list with the IDs of the tags of the current post. QuerySet
values_list()
returns a tuple with values for the specified fields. Passflat=True
to get the list in[1, 2, 3, ...]
format. - We get all posts with one of these tags, not including the current one.
- We use the
Count
aggregation function to generate thesame_tags
field, which contains the number of common tags. - Sort the results by number of common tags (in descending order) by
publish
to display the most recent [by publication date] posts among the first if several have the same number of common tags. We crop the results to get only the first four posts.
Add a similar_posts
object to the context dictionary for render()
:
return return(request,
'blog/post/detail.html',
{'post': post,
'comments': comments,
'new_comment': new_comment,
{' comment_form': comment_form,
'similar_posts': similar_posts})
Now you need to edit the blog/post/detail.html
template and add the following code before the list of post comments:
<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 %}
The post page should now look like this: You can now recommend similar posts to users.
django-taggit
also includes a similar_objects()
manager, which you can use to get posts with common tags. A look at all the django-taggit
managers can be found here: https://django-taggit.readthedocs.io/en/latest/api.html. You can also add a tag list to a post page based on the blog/post/list.html
template.