最近我正在修复一些与分页相关的错误。这是因为反向连接而发生的,并且因此出现了目标行。像这样:
class User(Base):
__tablename__ = "users"
id = sa.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
email = Column(String, index=True, nullable=False, unique=True)
class UserPermission(Base):
__tablename__ = "users_permissions"
id = sa.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
user_id = Column(
UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
)
permission = Column(String, nullable=False, index=True)
__table_args__ = (UniqueConstraint("user_id", "permission"),)
# results = db.execute(
# select(User).join(UserPermission).where(UserPermission.permission.in_(
# ["can_access_first_thing", "can_access_second_thing"]
# )
# ).unique().scalars().all()
Run Code Online (Sandbox Code Playgroud)
有时,执行填充的查询results将包含比现有行更多的行Users,因为对于每个用户来说,都会有多个UserPermission. 这会破坏任何基于offset/limit方法的分页。我对这个分页问题的解决方案是users在确定所有必需的用户 ID 后再次查询表:
base_query = select(User).join(UserPermission).where(UserPermission.permission.in_(
["can_access_first_thing", "can_access_second_thing"]
).with_only_columns(User.id)
results = db.execute(select(User).where(User.id.in_(base_query.subquery())))
Run Code Online (Sandbox Code Playgroud)
现在 SQLAlchemy 会针对这一行发出警告:SAWarning: Coercing Subquery object into a select() for use in IN(); please pass a select() construct explicitly。我的问题是如何正确重写现有查询,以便它返回相同的结果而不抛出此警告。
Sid*_*Sid 18
所以我现在觉得自己真的很蠢。返回到这个问题并彻底重读几次警告后,我开始意识到它所说的一切都表明我不需要将现有的 select 语句转换为子查询。然后,固定语句将如下所示:
base_query = select(User).join(UserPermission).where(UserPermission.permission.in_(
["can_access_first_thing", "can_access_second_thing"]
).with_only_columns(User.id)
results = db.execute(select(User).where(User.id.in_(base_query)))
Run Code Online (Sandbox Code Playgroud)
它几乎和以前一样,但是没有转换base_query为子查询。