SQLAlchemy - 如何使用连接选择x.id IS NOT NULL AS?

时间:2015-06-24 22:28:25

标签: python mysql sql sqlalchemy

我正在创建一个类似于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成员变量。

2 个答案:

答案 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)

这个查询不会更快,但它更容易与模型相关联,它还为您提供了有关用户的其他信息(名称等),我认为您无论如何都需要这些信息。