SQLAlchemy关联表一对多关系的详解

目录

ORM关系之一对多

示例1 

代码刨析 

示例2

 代码刨析


ORM关系之一对多

mysql级别的外键,还不够爽,必须拿到一个表的外键,然后通过这个外键再去另外一张表中查找,这样太麻烦了。

SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到了。

另外,可以通过backref来指定反向访问的属性名称。newss是指有多篇新闻。他们之间的关系是一个“一对多”的关系。

数据库层面

在数据库中,一对多关系通常通过在多的一方表中添加一个外键列,该列引用了另一方的主键。例如,在一个博客系统中,一个用户可以有多篇文章,那么在文章表中通常会包含一个指向用户表的外键。

ORM 层面

在 ORM 中,一对多关系通常通过在一个类中定义一个关联属性来实现。这个关联属性指明了与之相关联的类,以及在数据库中如何表示这种关系。

在 SQLAlchemy 中,可以使用 relationship 来定义一对多关系。比如:

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String, unique=True, nullable=False)
    articles = relationship('Article', back_populates='author', cascade='all, delete-orphan')

class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'))
    author = relationship('User', back_populates='articles')

查询操作 

在一对多关系中,可以轻松地通过关联属性来访问相关联的对象。例如,你可以通过 user.articles 访问一个用户的所有文章,或者通过 article.author 访问一篇文章的作者。

# 获取第一个用户的所有文章
user = session.query(User).first()
articles = user.articles

# 获取第一篇文章的作者
article = session.query(Article).first()
author = article.author

添加与删除 

在一对多关系中,你可以通过调用关联属性来添加新的对象。例如,你可以通过 user.articles.append(new_article) 将一篇新文章添加到一个用户的文章列表中。

# 创建一个新的文章,并将其关联到第一个用户
new_article = Article(title='New Article', content='Content of the new article')
user.articles.append(new_article)
session.commit()

还可以通过 user.articles.remove(article) 删除一个用户的某篇文章。

# 删除用户的第一篇文章
article_to_delete = user.articles[0]
user.articles.remove(article_to_delete)
session.commit()

以下是一个简单的示例,使用 SQLAlchemy 来创建一个用户和文章的一对多关系:

示例1 

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

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String, unique=True, nullable=False)
    articles = relationship('Article', back_populates='author', cascade='all, delete-orphan')

class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'))
    author = relationship('User', back_populates='articles')

# 创建数据库连接
engine = create_engine('sqlite:///example.db')

# 创建表格
Base.metadata.create_all(engine)

代码刨析 

在这个示例中,我们定义了两个类:UserArticle,并建立了一对多的关系:

  • User 类拥有一个属性 articles,它是一个关系属性,通过 relationship 函数来定义。这个关系会映射到 Article 类,并且通过 back_populates 参数指定了反向关系的属性名为 author

  • Article 类中有一个属性 author,也是一个关系属性,通过 relationship 函数定义。它映射到 User 类,并且通过 back_populates 参数指定了反向关系的属性名为 articles

在这个示例中,我们通过 relationship 来定义了一对多关系,并且通过 ForeignKey 来建立了外键关系,将 Article 表中的 author_idUser 表中的 id 关联起来。

这样,一个用户可以拥有多篇文章,而每篇文章只属于一个用户。

示例2

from sqlalchemy import Column,Integer,String,Text,ForeignKey
from sqlalchemy.orm import relationship


from db_util import Base,Session


class User(Base):
  __tablename__ = 't_user'
  id = Column(Integer,primary_key=True,autoincrement=True)
  uname = Column(String(50),nullable=False,name='name')
  # news = relationship('News')  # 不友好
  
  def __repr__(self):
    return f'<User: id={self.id} uname={self.uname}>'
    
# 1对多 ForeignKey的关键字要建立在 多一边
class News(Base):
  __tablename__ = 't_news'
  id = Column(Integer,primary_key=True,autoincrement=True)
  title = Column(String(50),nullable=False)
  content = Column(Text,nullable=False)
  uid = Column(Integer,ForeignKey('t_user.id'))
  
  user = relationship('User',backref='news') # 将主表的数据注入到这个字段


  def __repr__(self):
    return f'<News: id={self.id} title={self.title} content={self.content} uid={self.uid}>'


def create_data():
  user = User(uname = 'sxt') 
  news1 = News(title='Python',content='flask',uid = 1)
  news2 = News(title='MySQL',content='SQL',uid = 1)


  with Session() as ses:
    ses.add(user)
    ses.commit()


  with Session() as ses:
    ses.add(news1)
    ses.add(news2)
    ses.commit()


def query_data():
  with Session() as ses:
    # news1 = ses.query(News).first()
    # print(news1)
    
    # select u.id u.uname from t_news n left join t_user u n.uid = u.id where n.id = 1;
    news1 = ses.query(News).first()
    uid = news1.uid
    user = ses.query(User).first()
    print(user)




def query_data2():
  # 通地子表查询主表的数据
  with Session() as ses:
    news1 = ses.query(News).first()
    print(news1.user)




def query_data3():
  # 通地主表查找子表的数据
  with Session() as ses:
    user1 = ses.query(User).first()
    print(user1.news)




if __name__ == '__main__':
  # Base.metadata.create_all()
  # create_data()
  # query_data()
  # query_data2()
  query_data3()

 代码刨析

  1. User 类中包括了一个关联属性 news,它通过 relationship 来指明与 News 类的关系。而在 News 类中,使用了 ForeignKey 来建立了对 User 表的外键关联,并通过 relationship 指定了与 User 类的关联关系。

  2. create_data 函数创建了一个用户和两条新闻,并将它们添加到数据库中。

  3. query_data 函数中,你首先查询了一条新闻,然后获取了它的 uid(用户ID),接着通过用户ID查询了相应的用户。

  4. query_data2 函数中,首先查询了一条新闻,然后通过 news1.user 直接访问了与之关联的用户对象。

  5. query_data3 函数中,首先查询了一个用户,然后通过 user1.news 直接访问了与之关联的新闻对象。

SQLAlchemy中,一对多关系可以通过ForeignKey和relationship来定义。假设我们有两个,一个是User,一个是Post,每个用户可以发多篇文章。我们可以按照以下步骤进行操作: 1. 定义结构 ```python from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) posts = relationship("Post", back_populates="user") class Post(Base): __tablename__ = 'posts' id = Column(Integer, primary_key=True) title = Column(String) content = Column(String) user_id = Column(Integer, ForeignKey('users.id')) user = relationship("User", back_populates="posts") ``` 在这里,我们使用ForeignKey将Post与User关联起来,并使用relationship定义了之间的关系。在User中,我们使用back_populates参数来指定Post与之关联的属性名,并在Post中定义了一个user_id字段作为外键。 2. 创建Session并查询数据 ```python from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine = create_engine('sqlite:///example.db') Session = sessionmaker(bind=engine) session = Session() # 创建用户和文章对象并保存到数据库中 user = User(name='Alice') post1 = Post(title='Title 1', content='Content 1', user=user) post2 = Post(title='Title 2', content='Content 2', user=user) session.add(user) session.commit() # 查询用户及其关联的文章信息 query = session.query(User).options( relationship(User.posts)).filter_by(name='Alice') # 打印查询结果 for user in query.all(): for post in user.posts: print(f"User: {user.name}, Title: {post.title}, Content: {post.content}") ``` 在这个例子中,我们首先创建了一个用户对象和两个文章对象,并通过relationship建立了它们之间的一对多关系。然后我们将它们保存到数据库中。接着,我们使用query.options()函数来指定我们要查询的属性,其中relationship参数设置为User.posts,示我们要查询每个用户的所有文章。最后,我们通过for循环遍历查询结果并打印出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我还可以熬_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值