我有一个基本上是会话系统的应用程序(很像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
如果需要确保列出所有回复,那将会失败。
答案 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)
此外,父回复关系实际上不是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。