允许无限量的外键到同一模型的最佳方法是什么?

时间:2011-05-09 23:44:16

标签: django django-models django-templates django-views

我现在正在与django建立一个论坛,我想要它以便任何人都可以对任何其他人的评论发表评论。现在我的“评论”模型中有一个外键,它指向自身,所以我可以轻松地从任何评论中获得父评论。

在我的理论中,这很有效,因为从任何评论中我都可以获得所有的孩子评论,然后只是从那里继续分支以获得每个孩子的评论。但是,在将视图中的数据提供给模板时,我实际上无法实现这一点。

我希望有可能有无数次的儿童评论,因为谁知道讨论会持续多久,我不想随意限制它。我遇到的问题是你是否会从视图中获取所有这些评论而不会失去与父评论的关系?

目前这就是我的代码的伪代码:

#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 %}

显然,我甚至没有试图在这里得到所有孩子的评论,它只是得到孩子对第一篇文章的评论。我不明白的是,我怎样才能完成这些儿童评论中的每一条评论,然后获得所有这些评论,并为每个新评论继续这样做?

在视图中这样做是最有意义的,因为我可以在那里使用Django的QuerySet API,但我不知道如何在不丢失关系的情况下将所有注释传递给模板给他们的父母。我能想到的唯一想法是浏览视图中的所有注释并构建一个我刚刚传递的html字符串并简单地显示在模板中,但这似乎是一个可怕的想法因为它正在处理视图中的模板相关内容。

2 个答案:

答案 0 :(得分:1)

您可能希望了解如何使用django-mptt

等MPTT

这个可以由自定义过滤器实现,其中inclusion_tag包含自身,但会导致对您的数据库进行大量查询:

@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 %}

这个老问题可能很有意思:

How can I render a tree structure (recursive) using a django template?

答案 1 :(得分:0)

修改:对于未来的读者,不要这样做,因为内部for循环的comment变量在循环期间不替换外部comment变量执行,导致无限递归。的 /修改

如果您需要HTML页面中的递归树结构(即一堆嵌套的<div>标签),您可以编写一个递归的“注释”模板。

示例 :(未经测试)

{# comment.html #}
<p class='comment'>{{ comment.text }}</p>
{% if comment.children %}
   {% for comment in comment.children %}
      {% include "comment.html" %}
   {% endfor %}
{% endfor %}

for循环将comment模板变量绑定到每个子项,然后再包含它。

效果记录:除非您的评论集通常很短,否则这可能会非常慢。我建议您使评论不可编辑并缓存结果!

替代解决方案:如果您不需要递归HTML <div>标记,则可以编写一个生成器,执行结构的预先遍历并生成{{1} }对。这可能在渲染速度方面更有效。