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', }
配置修正说明
当前配置有两处需要完善:
- Comment父类的
__mapper_args__无需设置polymorphic_identity,它作为单表继承的基类,仅需指定polymorphic_on即可。 - 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ə
相关产品推荐
相关产品推荐

