sqlalchemy 表关系之一对一

今天我们就讲讲sqlalchemy最后一种关系: 一对一
  
首先,我们先创建user(父表)、arctire(子表)两张表,代码如下:

#父表
class User(Base):
    __tablename__ = "user"
    id = Column(Integer , primary_key=True , autoincrement=True)
    name = Column(String(50) , nullable=False)

#从表
class Arctire(Base):
    __tablename__ = "arctire"
    id = Column(Integer , primary_key=True , autoincrement=True)
    title = Column(String(50) , nullable=False)

    uid = Column(Integer,ForeignKey("user.id"))
    author = relationship("User" , backref="arctires")

表创建成功后,先不急着往表中添加数据,我们先查看下user.arctires 类型,代码如下

user = User(name = "tom")
arctire1 = Arctire(title = "title 1")
arctire2 = Arctire(title = "title 2")
print(type(user.arctires))

运行上述代码,结果如下:


我们再 from sqlalchemy.orm.collections import  InstrumentedList , 鼠标选中红色字体部分,双击进去。
结合上面两图,我们可知 user.arctires 的数据类型是 list。地球人都知道list有个append方法,下面我们就通过append这个方法来添加数据,代码如下
user = User(name = "tom")
arctire1 = Arctire(title = "title 1")
arctire2 = Arctire(title = "title 2")
user.arctires.append(arctire1)
user.arctires.append(arctire2)
session.add(user)
session.commit()

运行上述代码,结果如下:

OK,由上可知,数据已成功添加到数据表中。眼尖的小伙肯定发现,目前为止,这两张表还不是一对一关系,而是一对多。

上面讲的主要是让大伙知道 user.arctires数据类型,因为我们要做一对一,关键点就在这。接下来,为了方便演示一对一关系,我们重新新建一张UserExtend表(建议注释Arctire 模型),代码如下:( 注意需在user表中添加 extends = relationship("UserExtend");)

class UserExtend(Base):
    __tablename__ = "extend"
    id = Column(Integer , primary_key=True , nullable=False)
    city = Column(String(50) , nullable=False)
    uid = Column(Integer , ForeignKey("user.id"))
    user = relationship("User" , backref="extends")

我们先删除数据库的user、arctire表。然后在运行上诉代码,若无出错信息,则创建表成功。

接下来我们先看看 user.extend数据类型。代码如下
user = User(name = "tom")
extend = UserExtend(city = "shenzhen")
print(type(user.extends))

运行上诉代码,结果报错,报错信息如下:


为什么会报错?我们先不去谈报错的原因,我们先看看两个模型的relation属性。嘿嘿!!发现什么没???啥,没发现!!好吧,哪我就告诉大伙吧。
  
因为我们在User模型中定义了relationship属性,并赋值给 extends ,而我们又在UserExtend模型中定义了backref="extends",造成了冲突。解决办法:

1、去掉UserExtend模型中的backref属性
  
2、去掉User模型中的relatship属性

我们就试试第一种吧!(第二中我们下面讲代码优化时会讲到)
user = relationship("User")

我们再重新运行以下代码(查看 user.extends数据类型)

Base.metadata.drop_all()
Base.metadata.create_all()
user = User(name = "tom")
extend = UserExtend(city = "shenzhen")
print(type(user.extends))

没有报错!运行结果如下:

由上图可知,user.extends结果也是list类型,很显然我们这两张表还不是一对一关系,要实现我们所讲的一对一,其实很简单。只需在一对多关系基础上,在父模型的relation属性添加一个uselist参数进去,并将其值设为False(uselist字面意思为使用list,默认值为True:表示允许使用list);代码如下(红色文字为添加部分)

class User(Base):
    __tablename__ = "user"
    id = Column(Integer , primary_key=True , autoincrement=True)
    name = Column(String(50) , nullable=False)
    extends = relationship("UserExtend", uselist=False)

OK,我们再删除、创建模型,再查看 user.extends数据类型!运行结果如下


嗯、结果终于不是list类型了,看的都吐了!哪为啥是NoneType类型呢?原因很简单,因为我们user表中没有数据,不信我们可以试试


最后一个问题?我们怎么证明这两张表是一对一关系??

方法:向表中插入数据,然后再检测user.extend类型,如果运行结果为 <class '__main__.UserExtend'> ,说明这两张表是一对一关系。截图如下


最后我们对代码进行优化一下,去掉User模型的relationship属性,直接在UserExtend模型中定义,代码如下:( backref方法需从sqlalcehmy.orm中导入

user = relationship("User",backref=backref("extend" ,uselist=False))

上诉代码一样能实现一对一效果,在这里我就不演示了,有兴趣的可以试试。








SQLAlchemy中,一对一关系可以通过ForeignKey和relationship来定义。假设我们有两个,一个是User,一个是Profile,每个用户都有一个唯一的个人资料。我们可以按照以下步骤进行操作: 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) profile = relationship("Profile", uselist=False, back_populates="user") class Profile(Base): __tablename__ = 'profiles' id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('users.id')) email = Column(String) user = relationship("User", back_populates="profile") ``` 在这里,我们使用ForeignKey将Profile与User关联起来,并使用relationship定义了之间的关系。在User中,我们使用back_populates参数来指定Profile与之关联的属性名,并将uselist参数设置为False,示每个用户只有一个个人资料。 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') profile = Profile(email='alice@example.com', user=user) session.add(user) session.commit() # 查询用户及其关联的个人资料信息 query = session.query(User).options( relationship(User.profile, uselist=False)).filter_by(name='Alice') # 打印查询结果 for user in query.all(): print(f"User: {user.name}, Email: {user.profile.email}") ``` 在这个例子中,我们首先创建了一个用户对象和一个个人资料对象,并通过relationship建立了它们之间的一对一关系。然后我们将它们保存到数据库中。接着,我们使用query.options()函数来指定我们要查询的属性,其中uselist参数设置为False,示我们只需要查询每个用户的一个个人资料。最后,我们通过for循环遍历查询结果并打印出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值