【问题标题】:Sort parent comments along with their child comments in backend在后端对父评论及其子评论进行排序
【发布时间】:2021-09-27 08:11:27
【问题描述】:

我正在尝试在我的网站的后端使用 SQL Alchemy ORM 在 FastAPI 中创建评论部分,该网站包含 MySQL 数据库中的许多文章。

我有 3 个表 -> 用户、文章和评论。 user_idarticle_id 是注释表的外键。现在,它们是硬编码的。我尝试了一些递归函数,但效果不佳。由于数据库可以高效地存储和排序许多行,所以我更喜欢只在后端对 cme​​ts 进行排序。

我在 FastAPI 中有以下 models.py

class Comments(Base):
   __tablename__ = 'comment'
   id = Column(Integer, primary_key=True, index=True)
   text = Column(String(1000))
   user_id = Column(Integer)
   article_id = Column(Integer)
   created_date_time = Column(DateTime)
   parent_id = Column(Integer)

我发现了一个单行 SQL 查询,它有点接近我的需要,适用于回复主要 cmets(cmets 的 parent_id = NULL),但不适用于回复主要评论的回复并且不提供所需的时间顺序。

SELECT * FROM comment ORDER BY COALESCE(parent_id, id);

我想对数据进行排序,使父 cmets 按时间倒序排列,即顶部的最新父评论及其所有回复(对回复的回复)只有一级缩进,就像在 Instagram 上一样。回复(对回复的回复)应该按正常的时间顺序排列,即顶部的第一个 cmets 和底部的最新 cmets。例如:

id text user_id article_id created_date_time parent_id
7 3 28 41 2021-06-30 18:50:38 NULL
2 2 56 41 2021-06-27 10:00:04 NULL
3 2.1 28 41 2021-06-27 12:33:41 2
4 2.1.1 56 41 2021-06-28 20:07:09 3
5 2.2 12 41 2021-06-29 06:22:11 2
1 1 12 41 2021-06-27 09:20:44 NULL
6 1.1 28 41 2021-06-30 16:12:08 1

【问题讨论】:

    标签: python mysql sqlalchemy fastapi


    【解决方案1】:

    可能有一些更好的方法,但您可以通过某种特殊的标记/非规范化来做到这一点。

    例如,如果您将“thread_created_on”和“thread_id”添加到记录最顶部评论创建日期的 cmets,那么您可以通过平局获得您想要的。

    # RCO - reverse chronological order
    # CO - chronological order
    comments = session.query(Comments).order_by(
            Comments.thread_created_on.desc(), #threads together, RCO
            (Comments.thread_id == None).desc(), # True then False: thread comment top
            Comments.created_date_time.asc()) # nested comments CO)
    
    from datetime import datetime
    from sqlalchemy import (
        create_engine,
        UnicodeText,
        Integer,
        String,
        ForeignKey,
        UniqueConstraint,
        update,
        DateTime
    )
    from sqlalchemy.schema import (
        Table,
        Column,
        MetaData,
    )
    from sqlalchemy.sql import select
    from sqlalchemy.orm import declarative_base, relationship
    from sqlalchemy.orm import Session
    from sqlalchemy.exc import IntegrityError
    
    
    Base = declarative_base()
    
    
    engine = create_engine("sqlite://", echo=False)
    
    
    class Comments(Base):
       __tablename__ = 'comment'
       id = Column(Integer, primary_key=True, index=True)
       text = Column(String(1000))
       created_on = Column(DateTime)
       parent_id = Column(Integer, ForeignKey('comment.id'), nullable=True)
       thread_created_on = Column(DateTime)
       thread_id = Column(Integer, ForeignKey('comment.id'), nullable=True)
    
    
    Base.metadata.create_all(engine)
    
    def created_on(d):
        return datetime.strptime(d, "%Y-%m-%d %H:%M:%S")
    
    with Session(engine) as session:
        d1 = created_on('2021-06-27 09:20:44')
        thread1 = Comments(text='1', id=1, thread_created_on=d1, created_on=d1)
        thread11 = Comments(text='1.1', id=6, parent_id=1, thread_id=1, thread_created_on=d1, created_on=created_on('2021-06-30 16:12:08'))
        d2 = created_on('2021-06-27 10:00:04')
        thread2 = Comments(text='2', id=2, thread_created_on=d2, created_on=d2)
        thread21 = Comments(text='2.1', id=3, thread_id=2, parent_id=2, thread_created_on=d2, created_on=created_on('2021-06-27 12:33:41'))
        thread211 = Comments(text='2.1.1', id=4, thread_id=2, parent_id=3, thread_created_on=d2, created_on=created_on('2021-06-28 20:07:09'))
        thread22 = Comments(text='2.3', id=5, thread_id=2, parent_id=2, thread_created_on=d2, created_on=created_on('2021-06-29 06:22:11'))
        d3 = created_on('2021-06-30 18:50:38')
        thread3 = Comments(text='3', id=7, thread_created_on=d3, created_on=d3)
        session.add_all([thread1, thread11, thread2, thread21, thread211, thread22, thread3])
        session.commit()
        from sqlalchemy import desc, nulls_first
        comments = session.query(Comments).order_by(
            Comments.thread_created_on.desc(), #threads together, RCO
            (Comments.thread_id == None).desc(), # True then False: thread comment top
            Comments.created_on.asc()) # nested comments CO)
    
        props = ('id', 'text', 'created_on', 'parent_id', 'thread_id', 'thread_created_on')
        fmt = ''.join(['%20s']*len(props))
        print (fmt % props)
        for comment in comments:
            print (fmt % tuple([getattr(comment, prop) for prop in props]))
    
                      id                text          created_on           parent_id           thread_id   thread_created_on
                       7                   3 2021-06-30 18:50:38                None                None 2021-06-30 18:50:38
                       2                   2 2021-06-27 10:00:04                None                None 2021-06-27 10:00:04
                       3                 2.1 2021-06-27 12:33:41                   2                   2 2021-06-27 10:00:04
                       4               2.1.1 2021-06-28 20:07:09                   3                   2 2021-06-27 10:00:04
                       5                 2.3 2021-06-29 06:22:11                   2                   2 2021-06-27 10:00:04
                       1                   1 2021-06-27 09:20:44                None                None 2021-06-27 09:20:44
                       6                 1.1 2021-06-30 16:12:08                   1                   1 2021-06-27 09:20:44
    
    

    【讨论】:

    • 这种方法在理论上是有道理的,但在实际尝试时,只有thread_created_on 的命令被执行,而不是后两者,我不知道为什么。
    • @JoshinRexy 忘了我做了一个完整的例子,现在包括它
    • 真的很有帮助。如此接近我所需要的。但是说,如果我有一个 2.1.2 的评论(回复回复),它会出现在 2.3 的右下方而不是 2.1.1 的下方,因为我们正在对created_on 进行排序?
    • @joshinrexy 是的,我想我对你的描述感到困惑,评论树有固定的深度吗? IE。只有线程(1、2、3 等)、cmets(1.1、2.1 等)和对 cme​​ts(1.2.1)的回复?这更容易解决。或者你能回复不确定深度的回复吗,有点像 Reddit?(即。像 1.2.1.1.1.1....)
    • 我想有一个非固定的深度,以便回复可以出现在其父评论下方,但是在前端显示时,所有回复和回复的回复都会有一级缩进,就像 Instagram 一样。此外,不应该有一种正常的排序方式,而不是复制thread_created_onthread_id 的字段值。你有什么建议?
    猜你喜欢
    • 2020-05-04
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 2011-08-21
    相关资源
    最近更新 更多