如何在SQLAlchemy中实现关注/被关注关系

5 投票
1 回答
2411 浏览
提问于 2025-04-18 06:22

以推特为例。我们有一个 User 类,我们想把用户定义为 Follower(关注者)和 Followed(被关注者)。我们希望能有一个方法,比如 u.followers,这个方法可以返回一个列表,里面是关注用户 u 的所有用户。同样,u.following 应该返回一个列表,里面是用户 u 正在关注的所有用户。这个功能可以在 Ruby on Rails(RoR)中通过一种叫做“多对多关系”的方式来实现,具体可以参考 这篇文章

那么在 SQLAlchemy 中,我们该如何实现类似的功能呢?

1 个回答

11

这里有一个简单的例子。它创建了一个数据库和一个用户模型,并且设置了一个自我引用的多对多关系。最后,它展示了如何设置和获取用户的关注者和关注列表。

from sqlalchemy import create_engine, Column, Integer, String, Table, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, joinedload

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base(bind=engine)

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

    following = relationship(
        'User', lambda: user_following,
        primaryjoin=lambda: User.id == user_following.c.user_id,
        secondaryjoin=lambda: User.id == user_following.c.following_id,
        backref='followers'
    )

    def __str__(self):
        return self.name

    def __repr__(self):
        return '<User {0}>'.format(self)

user_following = Table(
    'user_following', Base.metadata,
    Column('user_id', Integer, ForeignKey(User.id), primary_key=True),
    Column('following_id', Integer, ForeignKey(User.id), primary_key=True)
)

Base.metadata.create_all()

u2 = User(name='jacob')
u3 = User(name='james')
u4 = User(name='victor')

u1 = User(name='david', followers=[u2, u3, u4])

session.add_all([u1, u2, u3, u4])
session.commit()

print u1.followers  # [<User jacob>, <User james>, <User victor>]
print u1.followers[0].following  # [<User david>]

这个内容在SQLAlchemy的文档中也有说明:自我引用的多对多关系

撰写回答