SQLAlchemy中关联Tag与User时如何仅过滤活跃用户?
问题解答
你的写法是错误的,具体问题如下:
Tag.users是用户集合类型的关系属性,不能用.contains(User.id)来写关联条件,contains是用来判断集合是否包含某个实例的方法,不适合用于JOIN的ON子句。Tag.users.is_active的写法逻辑错误,Tag.users是多个用户的集合,不是单个User对象,无法直接访问单个用户的is_active属性。
下面提供两种符合需求的正确写法,可根据你的实际场景选择:
场景1:仅返回存在活跃用户的标签,且标签关联的用户仅为活跃用户
这种写法会过滤掉没有任何活跃用户的标签,同时确保返回的每个标签的users集合里只有活跃用户:
all_tags_with_active_users = await session.scalars( select(Tag) .join(Tag.users) .filter(User.is_active == True) .distinct() # 避免同一个标签因关联多个活跃用户被重复返回 )
场景2:返回所有标签,标签关联的用户仅保留活跃用户(无活跃用户则users为空)
如果需要保留所有标签,不管有没有活跃用户,只是每个标签的users集合只显示活跃用户,需要用contains_eager来加载过滤后的关联数据:
from sqlalchemy import contains_eager all_tags_with_only_active_users = await session.scalars( select(Tag) .outerjoin(Tag.users) .options(contains_eager(Tag.users).filter(User.is_active == True)) .distinct() )
额外补充:如果希望每次访问Tag的users属性时都自动过滤活跃用户,可以直接在Tag的relationship定义里添加条件,这样不需要每次查询都手动写过滤逻辑:
users: Mapped[list["User"]] = relationship( "User", secondary=user_tag, back_populates="tags", lazy="selectin", primaryjoin="and_(Tag.id == user_tag.c.tag_id, User.is_active == True)" )
内容的提问来源于stack exchange,提问作者Librain
相关产品推荐
相关产品推荐

