I'm making a forum with django right now, and I want it so that anyone can comment on anyone else's comment. Right now I have a foreign key in my 'Comment' model that points back to itself so I can get the parent comment easily from any comment.
In my theory this worked great, because from any comment I could get all of its child comments, and then just kee开发者_Python百科p branching down from there to get every single child comment. However I'm having trouble actually implementing this when it comes to getting the data from the view to the template.
I want it to be possible to have an infinite number of child comments, because who knows how long a discussion will last and I don't want to arbitrarily limit it. The problem I'm having is would you get all of those comments from the view to the template without losing their relationship to their parent comment?
Currently this is what the psuedocode for my code looks like:
#the view
def comment_page(request, forum, comment_id):
#this is the main comment that all others will stem from
main_comment = Comment.objects.get(id=comment_id)
children_comments = main_comment.comment_set.all()
#the template
{% for comment in children_comments %}
<p class='comment'>{{comment}}</p>
{% endfor %}
Obviously I'm not even trying to get all the child comments here, it just gets child comments of the very first post. What I don't understand is how can I then go through each of these child comments and then get all of theirs, and keep doing that for each new comment?
It makes the most sense to do it in the view since I am able to use Django's QuerySet API in there, but I don't see how I would be able to pass all of the comments to the template without losing their relationship to their parent. The only idea I can think of is to go through all of the comments in the view and build up a string of html that I just pass and simply display in the template, but that seems like a horrible idea because it'd be dealing with template related stuff in the view.
You might want to look into using a MPTT such as django-mptt
this can be implemented by a custom filter with an inclusion_tag
that includes itself but causes a lots of queries to your db:
@register.inclusion_tag('children.html')
def comments_tree(comment):
children = comment.comment_set.all()
return {'children': children}
# children.html
<ul>
{% for child in children %}
<li> <a href="{{ child.get_absolute_url }}">{{ child }}</a></li>
{% if child.comment_set.count > 0 %}
{% comments_tree child %}
{% endif %}
{% endfor %}
</ul>
# your template
{% comments_tree comment %}
This older question is probably of interest:
How can I render a tree structure (recursive) using a django template?
Edit: to future readers, don't do this as the inner for
loop's comment
variable does not substitute the outer comment
variable during the loop execution, leading to infinite recursion. /Edit
If you need a recursive tree structure in your HTML page (i.e. a bunch of nested <div>
tags), you can write a recursive "comment" template.
Sample: (untested)
{# comment.html #}
<p class='comment'>{{ comment.text }}</p>
{% if comment.children %}
{% for comment in comment.children %}
{% include "comment.html" %}
{% endfor %}
{% endfor %}
The for loop binds the comment
template variable to each child before including itself.
Performance note: Unless your comment sets are often short, this will probably be very slow. I recommend that you make your comments non-editable and cache the result!
Alternate solution: If you don't need the recursive HTML <div>
tags, you can write a generator that performs a pre-order traversal of the structure and yields (depth, comment)
pairs. This would likely be far more efficient in rendering speed.
精彩评论