Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you add similar posts to a detail page using django

Tags:

python

django

I tried to show similar posts to an article in an aside column. A feauture sites like youtube and even stack overflow. Not having anyone to ask about it, I assumed articles listed on the side were ones with similar tags. But it's not working its saying nothing matches. this is what I had in my post_detail.html:

{% block content %}

<div class="row" style="margin-top: 70px">

    <div class="col-sm-8">
        {% if instance.image %}
            <img src='{{ instance.image.url }}' class="img-responsive" />
        {% endif %}


    <p>Share on:
    <a href="https://www.facebook.com/sharer/sharer.php?u={{ request.build_absolute_uri }}">
    Facebook
    </a>

    <a href="https://twitter.com/home?status={{ instance.content | truncatechars:80 | urlify }}%20{{ request.build_absolute_uri }}">
     Twitter
    </a>


    <a href='https://plus.google.com/share?url={{ request.build_absolute_uri }}'></a>


    <a href="https://www.linkedin.com/shareArticle?mini=true&url={{ request.build_absolute_uri }}&title={{
    instance.title }}&summary={{ share_string }}&source={{ request.build_absolute_uri }}">
     Linkedin
    </a>
    </p>

        <h1>{{ title }}<small>{% if instance.draft %}<span style="color:red"> Draft</span>{% endif %} {{instance.publish}}</small></h1>


        {% if instance.user.get_full_name %}
        <p>By {{ instance.user.get_full_name }}</p>
        {% else %}
            <p>Author {{ instance.user }}</p>
        {% endif  %}

        <p><a href='{% url "posts:list" %}'>Back</a></p>
        <p><a href='{% url "posts:delete" instance.id %}'>delete</a></p>
        <p>{{instance.content | linebreaks }}</p>
        <hr> 

    </div>

    <div class="panel panel-default pull-right" style="height: 1000px">
        <div class="panel-heading">
        <h3 class="panel-title">Similar Articles</h3>
      </div>
      ==========right here====================
        <div class="panel-body">
            {% for tag in instance.tags.all %}
            <h4> <a href="{% url 'posts:detail' slug=tag.slug %}"> {{ tag.title }}</a>  </h4><hr>
            {% endfor %}
        </div>
       ==========right here====================
    </div>


</div>

{% endblock content %}

and this is my view

 def post_detail(request, slug=None):
    instance = get_object_or_404(Post, slug=slug)
    if instance.publish > timezone.now().date() or instance.draft:
        if not request.user.is_staff or not request.user.is_superuser:
            raise Http404
    share_string = quote_plus(instance.content)
    context = {
        "title": "detail",
        "instance": instance,
        "share_string": share_string,
    }
    return render(request, "posts/post_detail.html", context)

if this approach is beyond syntax correction and needs to be rewritten. I don't mind writing it over the correct way. This is my second month working with Django. To me this way made sense but it's not working. And are sites like youtube which has a video and similar videos to the right of the main video, are those videos there because they share similar tags? any and all help is welcome.

like image 447
losee Avatar asked Dec 08 '25 05:12

losee


2 Answers

In the long run and to not reinvent the wheel using a reusable Django application already tried and tested is the sensible approach. In your case there is such app: django-taggit and is easy to use:

  1. You install it

    pip install django-taggit
    
  2. Add it to your installed apps:

    INSTALLED_APPS = [
        ...
        'taggit',
    ]
    
  3. Add its custom manager to the model on which you want tags

    from django.db import models
    
    from taggit.managers import TaggableManager
    
    class YourModel(models.Model):
        # ... fields here
    
        tags = TaggableManager()
    

    and you can use it in your views:

    all_tabs = instance.tags.all()
    

It even has a similar_objects() method which:

Returns a list (not a lazy QuerySet) of other objects tagged similarly to this one, ordered with most similar first.

EDIT

To retrieve similar posts you should use:

similar_posts = instance.tags.similar_objects()

and to get only the first, let's say, 5 similar posts:

similar_posts = instance.tags.similar_objects()[:5]

where instance is a instance of the Post model.

like image 117
doru Avatar answered Dec 09 '25 20:12

doru


you should let us know what is not matching.

your post_detail tries to find a Post with a tag's slug.

instance = get_object_or_404(Post, slug=slug)

I doubt that's what you intended.

get_object_or_404 either tries to find an exact match or raise error.
Since your original post has the tag, you will be getting the same post or multiple.

The following block of code is not what you said you wanted either.

        {% for tag in instance.tags.all %}
        <h4> <a href="{% url 'posts:detail' slug=tag.slug %}"> {{ tag.title }}</a>  </h4><hr>
        {% endfor %}

It lists all tags of the original post, doesn't list related post (via tag)

If you want to show related post, and you intent to use tag to define relatedness, define a method in your post model to return such related posts.

def get_related_posts_by_tags(self):
    return Post.objects.filter(tags__in=self.tags.all())

are those videos there because they share similar tags?

Not sure how they judge the relatedness, you should ask that in a separate question.
If I have to guess, it would be more than just tag comparison though.

** edit

Actually, proper term for relatedness is similarity.

You might find further info by googling document similarity.

{% for post in instance.get_related_post_by_tag %}
// href to post.absolute_url
{% endfor %}
like image 32
eugene Avatar answered Dec 09 '25 18:12

eugene



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!