我正在创建一个类似于Twitter的简单跟随系统,所以我有一个表,它是一个有向图,由以下字段组成: id,from_user(int),to_user(int )
class Follower(Base):
__tablename__ = 'user_follower'
id = Column(Integer, primary_key=True)
from_user = Column(ForeignKey('user.id'), nullable=False)
to_user = Column(ForeignKey('user.id'), nullable=False)
我在SQLAlchemy中基本上想要实现的是:
SELECT f1.id, f1.from_user, f1.to_user, f2.id
IS NOT NULL AS followed_back FROM user_follower f1
left outer join user_follower f2 on f1.from_user = f2.to_user and f1.to_user = f2.from_user
WHERE f1.to_user = :uid
换句话说,我需要生成一个名为followed_back的列,告诉用户是否也关注了一个关注者。
这在SQLAlchemy中似乎很成问题,因为在创建SELECT AS语句和连接的文档中似乎没有多少内容。此外,我不确定在查询创建对象后如何引用followed_back成员变量。
答案 0 :(得分:2)
这大致应该是您需要的查询:
f1 = aliased(Follower, name="f1")
f2 = aliased(Follower, name="f2")
query = (
session
.query(f1, (f2.id != None).label("followed_back"))
.filter_by(to_user=...)
.outerjoin(f2, (f1.from_user == f2.to_user) & (f1.to_user == f2.from_user))
)
答案 1 :(得分:2)
@Wolph的回答完全涵盖了你的问题。
作为替代选择:如果您的表Follower
仅用于启用多对多关系,则可以将其建模为 cleaner :
users_followers = Table(
'users_follower', Base.metadata,
Column('id', Integer, primary_key=True),
Column('from_user', ForeignKey('user.id')),
Column('to_user', ForeignKey('user.id')),
UniqueConstraint('from_user', 'to_user', name='UC_users_follower'),
)
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
followers = relationship(
'User',
secondary=users_followers,
primaryjoin=id == users_followers.c.to_user,
secondaryjoin=id == users_followers.c.from_user,
backref="followees",
# cascade='all',
)
在这种情况下,您可以按如下方式编写查询:
U1 = aliased(User, name="u1")
U2 = aliased(User, name="u2")
q = (session
.query(
U1, U2,
U2.followers.any(User.id == U1.id).label("followed_back"),
)
.join(U2, U1.followers)
# .filter(...)
# .order_by(...)
)
for u1, u2, follows in q:
print(u1, u2, follows)
这个查询不会更快,但它更容易与模型相关联,它还为您提供了有关用户的其他信息(名称等),我认为您无论如何都需要这些信息。