【问题标题】:Converting pymysql Comment objects to tree recursively将pymysql Comment对象递归转换为树
【发布时间】:2017-05-20 01:59:48
【问题描述】:

我正在尝试创建一个评论系统作为爱好项目的一部分,但我无法弄清楚一旦从数据库中获取评论对象后如何对它们进行递归排序。我正在使用具有以下数据模型的关系数据库:

class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    comment = Column(String(), nullable=False)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    post_id = Column(Integer, ForeignKey('posts.id'), nullable=False)
    parent_id = Column(Integer, ForeignKey('comments.id'), nullable=False)

从数据库中获取数据后,我需要在树中对这些对象进行排序。例如输入可以是:

comments = [
            <models.Comment object at 0x104d80358>,
            <models.Comment object at 0x104d803c8>,
            <models.Comment object at 0x104d80470>, 
            <models.Comment object at 0x104d80518>,
            <models.Comment object at 0x104d805c0>,
            <models.Comment object at 0x104d80668>
           ]

预期结果可能是:

comment_dict = {1: {'comment':<Comment.object>, 'children':[]},
               {2: {'comment':<Comment.object>, 'children':[<Comment.object>, ...]},
               {3: {'comment':<Comment.object>, 'children':[]},
               {4: {'comment':<Comment.object>, 'children':[<Comment.object>, ...]} ...

任何评论对象都可以有无限数量的子对象。几乎就像 reddit 和其他类似社交媒体网站上使用的评论系统一样。 对于渲染,我使用的是烧瓶和 Jinja,并且可能会执行我在文档中找到的类似操作:

<ul class="sitemap">
{%- for item in sitemap recursive %}
    <li><a href="{{ item.href|e }}">{{ item.title }}</a>
    {%- if item.children -%}
        <ul class="submenu">{{ loop(item.children) }}</ul>
    {%- endif %}</li>
{%- endfor %}

在此之前我如何对数据进行排序是我没有弄清楚的。

【问题讨论】:

    标签: python algorithm sqlite recursion pymysql


    【解决方案1】:

    非常简单的方法是这样的:

    def comments_to_dict(comments):
        result = {}
        for comment in comments:
            result[comment.id] = {
                'comment': comment,
                'children': []
            }
        for comment in comments:
            result[comment.parent_id]['children'].append(comment)
        return result
    

    所以首先用children 填充根元素为空,然后在第二遍中填充子元素。这可以通过只通过comments 进一步改进:

    def comments_to_dict(comments):
        result = {}
        for comment in comments:
            if comment.id in result:
                result[comment.id]['comment'] = comment
            else:
                result[comment.id] = {
                    'comment': comment,
                    'children': []
                }
    
            if comment.parent_id in result:
                result[comment.parent_id]['children'].append(comment)
            else:
                result[comment.parent_id] = {
                    'children': [comment]
                }
        return result
    

    这里的解决方案符合您向我们展示的预期输出。


    如果你想要一棵真正的树,那么试试这个

    def comments_to_dict(comments):
        index = {}
        for comment in comments:
            index[comment.id] = {
                'comment': comment,
                'children': []
            }
        for obj in index.itervalues():
            pid = obj['comment'].parent_id
            index[pid]['children'].append(obj)
        return index
    

    【讨论】:

    • 但这会允许无限深的 cmets 树吗?
    • @Marius 任意深度树可以分两遍实现。我已经更新了答案。这可以像以前一样在单遍中实现。我会把它留给你作为练习。
    猜你喜欢
    • 2020-04-23
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    相关资源
    最近更新 更多