Home > database >  how to extract data from queryset in django
how to extract data from queryset in django

Time:06-04

i am trying to add reply to my blog project's comments section here is the models.py

class Comment(models.Model):
    blog= models.ForeignKey(Blog, on_delete=models.CASCADE,related_name='Blog_comment')
    user=models.ForeignKey(User,on_delete=models.CASCADE, related_name='user_comment')
    comment=models.TextField(default='Your Comment')
    parent =  models.ForeignKey('self', on_delete=models.CASCADE,null=True,related_name='paren_comment')
    comment_date=models.DateTimeField(auto_now_add=True)

here is the replies that i passed to the template through replies key

replies=Comment.objects.filter(blog=blog).exclude(parent=None)

it's type is

<class 'django.db.models.query.QuerySet'>

So i am running a loop for comment where i can get comment id by comment.id. In that loop i want to run another loop for replies and compare if their(replies) parent.id is equal to the comment.id; then print them in template under the comment. something like this

{% if comment.id == reply.parent.id %}
                                {{reply}}
                            {% endif %}

i just want to compare by replies parent id with the comment.id; if they match then allow replies under that comment.

how can i do that? should i use some custom filter?( kindly ask me if there is more to be explained about this problem)

CodePudding user response:

The way you have done it above, it will only work for one level. You can't check for replies of replies. To do that, you need to recursively apply the detection of children as you don't know how many levels of replies there are.

One way to do it is involves providing a means to get the children of a comment. Try adding the following method to your model

class Comment(models.Model):
    ...
    def get_replies(self): 
    #we're using the parent 'related_name' get all the comments that are children of this one 
    #(maybe rename the related_name to 'children')
        return self.paren_comment.all() 

Next we get a list of all the first comments (those without parents) in views.py and pass it to our template via context

#get a list of all first_comments for a blog
first_comments=Comment.objects.filter(blog=blog, parent=None)
context['comments'] = first_comments

Use a base template to start things off, eg, template.html

    {{blog.content}}
    {% for comment in comments %}
        <!-- we pass the comment presentation off to a sub-template -->
        <% include comment.html with comment = comment %>
     {% endfor %}

Then each comment calls another template that can also call itself if there are more children.

comment.html

    <!-- show the actual comment-->
    {{comment.comment}}

    <!-- next we use our model function to get any comment children-->
    {% for reply in comment.get_replies %}   
        <!-- we use blockquote here to provide a simple form of indentation -->
        <blockquote>        
            {% include 'comment.html' with comment=reply%}   
        </blockquote>
    {% endfor %}

Each level of

This should work (assuming I haven't typoed horrendously), but you might find it a little slow for large numbers of comments, and django may object if you go too many layers deep. For industrial strength threaded comments you want to use something like Django-mptt, which implements Modified Preorder Tree Traversal and is perfect for comments, but a little more technical to create. A guide to using it for threaded comments can be found here

CodePudding user response:

you have to pass replies as a context while rendering html

return render(
            request,
            "app_name/file_name.html",
            {"replies": replies},
        )

and then in template iterate like this

{% for reply in replies %}
     {{reply or reply.field_name_from_queryset }}
{% endfor %}

  • Related