Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement following/followers relationship in SQLAlchemy

Take twitter as an example. We have a User class, and we want to define a user as Follower and Followed.We would like to have a method like this u.followers, which returns a list of users that follow this user u. Similarly, u.following should return a list of the users, this user u is following. This can be implemented in RoR through a has-many-through relationship, like so in this article.

How can we do the similiar thing in SQLAlchemy?

like image 433
zsljulius Avatar asked Jan 11 '23 14:01

zsljulius


1 Answers

Here's a minimal example. It sets up a database and a User model with a self-referential many-to-many relationship. Finally, it shows how to set and get a user's followers and following lists.

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>]

This is also described in SQLAlchemy's documentation: Self-Referential Many-to-Many Relationship

like image 196
davidism Avatar answered Jan 13 '23 22:01

davidism