You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLAlchemy 2多态关联配置验证与评论获取方法咨询

SQLAlchemy 2 多态关联配置与查询方案

我正在使用SQLAlchemy 2,拥有Portfolio(作品集)和Comment(评论)模型,已建立如下多态关联以支持对作品集和评论本身进行评论,需将两类评论存储在数据库同一张表中,不确定当前关联配置是否正确。请问如何通过该多态关联获取作品集的评论以及评论下的子评论?

当前模型代码

Portfolio模型

class Portfolio(BaseModel):
    __tablename__ = 'portfolio_portfolio'
    id: Mapped[intpk]
    user_id: Mapped[int] = mapped_column(ForeignKey('user_user.id'))
    user: Mapped['User'] = relationship(back_populates='portfolios')
    title: Mapped[str] = mapped_column(String(255))
    description: Mapped[str] = mapped_column(Text)
    
    comments: Mapped[list['Comment']] = relationship(
        'Comment',
        primaryjoin="and_(Portfolio.id == Comment.commentable_id, Comment.commentable_type=='portfolio_portfolio')",
    )

Comment模型

class Comment(BaseModel):
    __tablename__ = 'core_comment'
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey('user_user.id'))
    commentable_type: Mapped[str] = mapped_column(String)
    commentable_id: Mapped[int]
    text: Mapped[str] = mapped_column(Text)
    __mapper_args__ = {
        'polymorphic_on': commentable_type,
    }

多态子类模型

class PortfolioComment(Comment):
    __mapper_args__ = {
        'polymorphic_identity': Portfolio.__tablename__,
    }

class CommentComment(Comment):
    __mapper_args__ = {
        'polymorphic_identity': 'comment_comment',
    }

配置修正说明

当前配置有两处需要完善:

  1. Comment父类的__mapper_args__无需设置polymorphic_identity,它作为单表继承的基类,仅需指定polymorphic_on即可。
  2. Comment模型缺少子评论的关联关系,无法直接获取评论下的嵌套评论。

修正后的Comment模型如下:

class Comment(BaseModel):
    __tablename__ = 'core_comment'
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey('user_user.id'))
    commentable_type: Mapped[str] = mapped_column(String)
    commentable_id: Mapped[int]
    text: Mapped[str] = mapped_column(Text)
    # 添加子评论关联
    replies: Mapped[list['Comment']] = relationship(
        'Comment',
        primaryjoin="and_(Comment.id == Comment.commentable_id, Comment.commentable_type=='comment_comment')",
        remote_side=[id]
    )
    __mapper_args__ = {
        'polymorphic_on': commentable_type,
    }

Portfolio模型的comments关联配置是正确的,也可以利用多态类型简化写法:

comments: Mapped[list[PortfolioComment]] = relationship(
    PortfolioComment,
    primaryjoin="Portfolio.id == PortfolioComment.commentable_id"
)

这种写法直接关联到PortfolioComment子类,SQLAlchemy会自动带上commentable_type='portfolio_portfolio'的过滤条件。

查询方法

1. 获取指定作品集的所有评论(包含子评论)

使用selectinload或joinedload预加载子评论,避免N+1查询:

from sqlalchemy.orm import selectinload

# 方式1:通过Portfolio模型查询
portfolio = session.get(Portfolio, portfolio_id, options=[
    selectinload(Portfolio.comments).selectinload(Comment.replies)
])
# portfolio.comments 为该作品集的所有评论,每个comment.replies对应其子评论

# 方式2:直接查询PortfolioComment
comments = session.query(PortfolioComment)\
    .filter(PortfolioComment.commentable_id == portfolio_id)\
    .options(selectinload(PortfolioComment.replies))\
    .all()

2. 获取单条评论的子评论

# 预加载子评论
comment = session.get(Comment, comment_id, options=[selectinload(Comment.replies)])
# 直接访问comment.replies即可获取该评论的子评论列表

3. 递归获取多级子评论

如果需要获取评论的所有层级子评论,可以使用递归CTE查询:

cte = session.query(Comment)\
    .filter(Comment.id == parent_comment_id)\
    .cte(recursive=True)

cte = cte.union(
    session.query(Comment)\
        .filter(Comment.commentable_id == cte.c.id, Comment.commentable_type == 'comment_comment')
)

all_replies = session.query(Comment).from_statement(cte).all()

内容的提问来源于stack exchange,提问作者Vahid Həsənzadə

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:33:30