django中的多线程对话(如Reddit)

时间:2010-05-28 13:37:28

标签: django model

我有一个基本上是会话系统的应用程序(很像reddit)。

如果帖子可以有多个回复,回复并且有多个回复,并且对回复的回复可以有多个回复(等等)

我已经制作了这样的模型:

class Discussion(models.Model):
    message = models.TextField()
    replies = models.ManyToManyField('self')

和视图:

discussions = Discussions.objects.all()

,模板如下所示:

{% for discussion in discussions %}
    {{ discussion.message }}
{% endfor %}

我如何制作一个系统,我可以输出这样的所有回复?

discussion
    reply
        reply
    reply
        reply
            reply
                reply

如果需要确保列出所有回复,那将会失败。

3 个答案:

答案 0 :(得分:5)

除非回复可以是对多个帖子的回复,否则ManyToManyField不是您想要的。您只需要一个ForeignKey

class Discussion(models.Model):
    message = models.TextField()
    reply_to = models.ForeignKey('self', related_name='replies', 
        null=True, blank=True)

然后,您可以使用Discussion.replies进行讨论的回复。

不幸的是,没有办法在Django的模板语言中进行递归,所以你必须要么1)运行一个递归函数来得到一个“扁平”的回复列表,并把它放在上下文中,或者2)写一个可以递归调用的函数,它使用模板生成每个级别,如下所示:

_DiscussionTemplate = Template("""
<li>{{ discussion.message }}{% if replies %}
    <ul>
        {% for reply in replies %}
        {{ reply }}
        {% endfor %}
    </ul>
{% endif %}</li>
""".strip())

class Discussion(models.Model):
    message = models.TextField()
    reply_to = models.ForeignKey('self', related_name='replies', 
        null=True, blank=True)

    @property
    def html(self):
        return _DiscussionTemplate.render(Context({
            'discussion': self,
            'replies': [reply.html() for reply in self.replies.all()]
        }))

然后在您的顶级模板中,您只需要:

<ul>
    {% for d in discussions %}
    {{ d.html }}
    {% endfor %}
</ul>

根据需要应用CSS,使其看起来不错。

编辑:根讨论是Discussion.objects.filter(reply_to=None)中的讨论。并且所有代码_DiscussionTemplate都包含在您的models.py中。这样,_DiscussionTemplate在模块加载时初始化一次。

编辑2:将HTML放在模板文件中非常简单。将设置_DiscussionTemplate的视图代码更改为:

_DiscussionTemplate = loader.get_template("discussiontemplate.html")

然后创建discussiontemplate.html

<li>{{ discussion.message }}{% if replies %}
    <ul>
        {% for reply in replies %}
        {{ reply }}
        {% endfor %}
    </ul>
{% endif %}</li>

根据需要设置模板文件的路径。

答案 1 :(得分:1)

查看django-threadedcomments

此外,父回复关系实际上不是ManyToMany - 它是父子OneToMany,因为评论(在传统的线程评论模型中,无论如何)只能是回复,最多,另一条评论。

答案 2 :(得分:1)

第一步是修复你的模型。抬头而不是俯视。

class Discussion(models.Model):
    message = models.TextField()
    parent = models.ForeignKey(Discussion, null=True, blank=True)

    def get_children(self):
        return Discussion.objects.filter(parent=self)

当某些东西没有父级时,它就是一个根线程。当它发生时,它就是一个回复。

您的显示逻辑需要稍微改变一下。而不是迭代所有评论,迭代顶级帖子。您的comment.html文件可能如下所示:

{{ comment.message }}
{% for comment in comment.get_children %}
    {% include comment.html %}
{% endfor %}

在您的主模板中,您有:

{% for comment in base_comments %}
    {% include 'comment.html' %}
{% endfor %}

在您看来,将'base_comments':Discussion.objects.filter(parent=None)添加到您的上下文中。

当然有一个UI元素,你需要格式化和处理回复过程,但我会把它留给你。

不要忘记你可以很容易地将所有这些外包出去。我非常有效地使用Disqus。