Python中SQLAlchemy不使用ForeignKey如何进行关联?
官方文档
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", back_populates="addresses")
def __repr__(self):
return "<Address(email_address='%s')>" % self.email_address
这里 ForeignKey('users.id') 是必须的么? 可以不使用外键强制约束吗?
Python中SQLAlchemy不使用ForeignKey如何进行关联?
可以啊,自己写程序实现关联呗。
在SQLAlchemy里,不用ForeignKey也能做关联,核心是靠relationship()和手动指定关联条件。下面是个完整例子:
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
# 不用ForeignKey,用primaryjoin指定关联条件
addresses = relationship(
"Address",
primaryjoin="User.id == Address.user_id", # 手动指定关联条件
back_populates="user"
)
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer) # 这里没有ForeignKey约束
user = relationship(
"User",
primaryjoin="Address.user_id == User.id",
back_populates="addresses"
)
# 创建数据库
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# 测试数据
user = User(name="张三")
addr1 = Address(email="zhangsan@example.com", user_id=1)
addr2 = Address(email="zhangsan2@example.com", user_id=1)
user.addresses = [addr1, addr2]
session.add(user)
session.commit()
# 查询测试
queried_user = session.query(User).first()
print(f"用户: {queried_user.name}")
for addr in queried_user.addresses:
print(f" 邮箱: {addr.email}")
关键点:
relationship()里的primaryjoin参数用来指定关联条件- 数据库层面没有外键约束,但ORM层面关联正常
- 查询和操作跟有外键时一样
这种方案适合:数据库没外键约束、跨数据库关联、或者用已有数据库结构的情况。不过要注意数据一致性得自己维护。
总结:用primaryjoin手动指定关联条件就行。
当然可以啦, 比如说你有一个 users 表:
class User(Base):
tablename = “users”
id_ = Column(Integer, primary_key=True)
name = Column(String(16))
你还有一个 address 表:
class Address(Base):
tablename = “address”
id_ = Column(Integer, primary_key=True)
place = Column(String(256))
user_id = Column(Integer)
user = relationship(“User”, uselist=False, primaryjoin=foreign(user_id) == remote(User.id_))
你只需要在 relationship 里用 primaryjoin 来手动指定 join 关系就可以了, 前提是已经导入了 User. 这部分也在文档里提到了
此外还可以写成
relationship(“User”, uselist=False, foreign_keys=user_id, primaryjoin=“Address.user_id==User.id_”)
这种写法同样要求已经导入 User, 但是会被 ide 识别为 unused import. 所以建议使用第一种
#2
user = relationship(“User”, uselist=False, primaryjoin=foreign(user_id) == remote(User.id_))
这不还是有 foreign 么
…首先你是不是被降权了,没收到通知
其次虽然这里有 foreign,但实际上在数据库里面是不会有外键约束的。这里只是把这个 user_id 看作了外键,以便于进行 join 查询,和他本身是不是外键是没关系的。
#4
好像是吧……
表示在 sqlalchemy 里并没有 foreign 和 remote 两个方法
no named module
#4
好吧,在 sqlalchemy.orm 中

