python - 多对多关系上的SqlAlchemy外键错误
问题描述
我正在尝试在 SqlAlchemy 中建立基本的多对多关系。我能够使用 db.create_all() 成功创建数据库,但是在尝试从数据库中检索任何记录时遇到错误。
class Geo(db.Model):
__tablename__ = 'geos'
geo = db.Column(db.Integer, primary_key=True)
states = db.relationship("State", secondary='geos_states')
class State(db.Model):
__tablename__ = 'states'
state_short = db.Column(db.String, primary_key=True)
geos = db.relationship("Geo", secondary='geos_states')
class GeoState(db.Model):
__tablename__ = 'geos_states'
id = db.Column(db.Integer, primary_key=True)
geo_id = db.Column(db.Integer, db.ForeignKey('geos.geo')),
state_short_id = db.Column(db.String, db.ForeignKey('states.state_short'))
错误如下:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Could not determine join condition between parent/child tables on relationship Geo.states - there are no foreign keys linking these tables via secondary table 'geos_states'. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.
解决方案
您使用的模式是 SQLAlchemy 中多对多关系模式的变体。
通常你会做的是以下
geostates_association_table = Table(
'geo_states', Base.metadata,
db.Column(
'geo_id', db.Integer,
db.ForeignKey('geos.geo')
),
db.Column(
'state_short_id', db.String,
db.ForeignKey('states.state_short')
)
)
class Geo(db.Model):
__tablename__ = 'geos'
geo = db.Column(db.Integer, primary_key=True)
states = db.relationship(
"State",
secondary= geostates_association_table,
back_populates='geos'
)
class State(db.Model):
__tablename__ = 'states'
state_short = db.Column(
db.String,
primary_key=True
)
geos = db.relationship(
"Geo",
secondary=geostates_association_table,
back_populates='states'
)
我认为这是您所需要的,因为在多对多关系中的映射表上似乎不需要任何其他列。但是,如果您这样做了,您将需要使用您最初正在做的关联对象模式。在这种情况下
class Geo(db.Model):
__tablename__ = 'geos'
geo = db.Column(
db.Integer,
primary_key=True
)
states = db.relationship(
"GeoState",
back_populates="geos"
)
class State(db.Model):
__tablename__ = 'states'
state_short = db.Column(
db.String,
primary_key=True
)
geos = db.relationship(
"GeoState",
back_populates="states"
)
class GeoState(db.Model):
__tablename__ = 'geos_states'
# Notice how we set primary keys on both the fields
geo_id = db.Column(
db.Integer,
db.ForeignKey('geos.geo'),
primary_key=True
),
state_short_id = db.Column(
db.String,
db.ForeignKey('states.state_short'),
primary_key=True
),
some_other_field = db.Column(
db.String
)
geos = relationship("Geo", back_populates="states")
states = relationship("State", back_populates="geos")
请注意,在这种情况下,您将在关系列表中获得的State
内容Geo
实际上是GeoState
对象。如果您想使用关联对象模式,但让关系列表由它们各自的对应对象填充。您可以使用 AssociationProxy sqlalchemy 扩展,您可以在此处找到文档
供你参考,
关联对象模式记录在这里
此处记录了基本的多对多模式
推荐阅读
- php - 如何使用 php 中的 NATS API 使用用户名或电子邮件登录?
- spring - Spring Boot ManyToMany - StackOverflow - JPA,Hibernate
- c# - 用于 CSS 隔离的 Blazor 组件中间的链接标记
- java - 在 localhost 上找不到或禁止 404
- javascript - 找到总长度为 10 的数组的随机组合,可拆分为两组,每组 5 个
- php - PHP小数点和是可能的
- sql-server - 如何在一个连接下查看特定服务器的所有数据库?
- c++ - 我应该如何使用 remove_if 删除两个数字范围内的元素
- android - 网络原生模块 android 在处理 android studio 程序时无法在 react-native progam for android 中工作
- strategy-pattern - 基于其他策略的实施策略模式