Code前端首页关于Code前端联系我们

SQLAlchemy数据表独立关联代码

terry 2年前 (2023-09-24) 阅读数 51 #后端开发

在讲数据表关系时,默认是数据表之间的关系“一对多、一对一、多对多等”。在实际应用中,我们经常会遇到数据表中的关联,比如现在网上的“关注者”、“关注者”等术语。两者都在用户范围内,只是两个用户之间的关系。

关系是表示现实世界实体以及它们之间的各种连接的单一数据结构。

使用SQLAlchemy建立数据表之间的关系,之前的文章SQLAlchemy定义关系已经介绍过了。今天我们主要看单个数据表中的关系。

数据表中的一对多关系

数据表中的一对多关系有其自己的关系,通常是父子关系。我们通过引用表中父亲的 id 来做到这一点,然后通过反向链接获取孩子的信息。在这里,我们使用用户及其关注者实现一个数据类。

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    followed_id = Column(Integer, ForeignKey("user.id"))
    followers = relationship("User", remote_side=[id], backref='user')

上例中,可以从follower处获取follower的信息,follower可以通过反向链路接收follower发来的信息。这里我们假设一个用户只能关注一个人,一个用户可以被多个用户关注。

使用SQLAlchemy的完整示例代码如下:

# -*- coding:utf-8 -*-

from sqlalchemy import (
    create_engine,
    Column,
    Integer,
    String,
    DateTime,
    Text,
    ForeignKey,
    Table,
    MetaData,
)
from sqlalchemy.orm import relationship,backref,sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    followed_id = Column(Integer, ForeignKey("user.id"))
    followed = relationship("User", remote_side=[id], backref='user')

engine = create_engine('sqlite:///./test.sqlite')
db_session = sessionmaker(bind=engine)
session = db_session()
Base.metadata.create_all(engine)

user1 = User(name='user1')
user2 = User(name='user2')
user3 = User(name='user3')
session.add(user1)
user2.followed = user1
session.add(user2)
user3.followed = user1
session.add(user3)
session.commit()

user = session.query(User).filter(User.name == 'user2').first()
print(user.name + 'followed:')
print(user.followed.name)

user = session.query(User).filter(User.name == 'user1').first()
print(user.name + 'followers:')
for n in user.user:
    print(n.name)
user4 = User(name='user4')
user4.followed = user
session.add(user4)
session.commit()

user = session.query(User).filter(User.name == 'user1').first()
print(user.name + 'followers:')
for n in user.user:
    print(n.name)

上例运行结果如下:

user2followers:
user1
user1followed:
user2
user3
user1followed:
user2
user3
user4

数据表中的多对多关系

还有其他自解的例子数据表中的许多关系- for-many 例如关注者与关注者之间的完整关系、Python中父类与子类之间的关系等。在SQLAlchemy中,多对多关系必须借助帮助来实现。来自关系表。关联的多对多关系也需要关联表,但关联表是同一个数据表。

followers = Table('followers', Base.metadata,
    Column('follower_id', Integer, ForeignKey('user.id')),
    Column('followed_id', Integer, ForeignKey('user.id'))
)

创建关系表后,需要通过关系来创建关系。在两个数据表之间的多对多关系中,只需要指定辅助参数为关系表即可,但是关联关系表中的follower_id和follwed_id是同一个数据表的id,SQLAlchemy无法区分二。此时,我们就得用另一种方法来区分。

这个时候就需要用到primaryjoin参数和 secondaryjoin关系参数。 PrimaryJoin 表达式表示左表和联接表之间的联接,SecondaryJoin 表示联接表和右表之间的联接。

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    followed = relationship(
        'User',
        secondary=followers,

        # primaryjoin 指明了右侧对象关联到左侧实体(关注者)的条件
        # 也就是根据左侧实体查找出对应的右侧对象
        # 执行 user.followed 时候就是这样的查找
        primaryjoin=(followers.c.follower_id == id),

        # secondaryjoin 指明了左侧对象关联到右侧实体(被关注者)的条件
        # 也就是根据右侧实体找出左侧对象
        # 执行 user.followers 时候就是这样的查找
        secondaryjoin=(followers.c.followed_id == id),

        # backref 定义了右侧实体如何访问该关系
        # 也就是根据右侧实体查找对应的左侧对象
        # 在左侧,关系被命名为 followed
        # 在右侧使用 followers 来表示所有左侧用户的列表,即粉丝列表
        backref=backref('followers', lazy='dynamic'),
        lazy='dynamic'
        )

在使用中,我们可以通过follow获取follower列表,通过followers获取follow再列表。但实际上follow和followers是两个不同的SQL语句。我们可以通过print打印两条语句。描述如下:

  1. user.followed 内容如下
SELECT user.id AS user_id, user.name AS user_name
FROM user, followers
WHERE followers.follower_id = ? AND followers.followed_id = user.id
  1. user.followers 内容如下
SELECT user.id AS user_id, user.name AS user_name
FROM user, followers
WHERE followers.followed_id = ? AND followers.follower_id = user.id

作者:keinYe

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门