【问题标题】:Multi-thread conversation in django (like Reddit)django 中的多线程对话(如 Reddit)
【发布时间】:2011-02-25 03:27:40
【问题描述】:

我有一个应用程序,它本质上是一个对话系统(很像 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

为了确保列出所有回复,这将下降到最低限度。

【问题讨论】:

    标签: django model


    【解决方案1】:

    查看django-threadedcomments

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

    【讨论】:

    • 那个链接超出了我的想象。还有其他解决方案吗?
    【解决方案2】:

    第一步是修复模型。向上看而不是向下看。

    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)
    

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

    您的显示逻辑需要稍作更改。不是迭代所有 cmets,而是迭代顶级帖子。您的 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。

    【讨论】:

      【解决方案3】:

      除非回复可以是对多个帖子的回复,否则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>
      

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

      【讨论】:

      • _DiscussionTemplate 去哪儿了?它在我的模型中吗?我必须导入模板吗?
      • symmetrical=False 抛出一个错误,所以我删除了它,这仍然有效吗?
      • 我怎么知道哪些是根讨论?
      • 出色的答案。非常感谢。
      • 只是跟进,效果很好。但是,有没有办法将模板从模型移动到它自己的模板中?所以它可以驻留在 templates/includes/discussiontemplate 中?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      • 2012-06-29
      • 1970-01-01
      • 2022-10-25
      相关资源
      最近更新 更多