简体   繁体   English

SqlAlchemy 多对多关系上的外键错误

[英]SqlAlchemy Foreign Key Error on Many to Many Relationship

I am attempting to set up a basic many-to-many relationship in SqlAlchemy.我正在尝试在 SqlAlchemy 中建立基本的多对多关系。 I am able to successfully create the database using db.create_all() but I run into an error when trying to retrieve any records from the database.我能够使用 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'))

The error is as follows:错误如下:

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.

The pattern you are using is a variant on the many-many relationship pattern in SQLAlchemy.您使用的模式是 SQLAlchemy 中多对多关系模式的变体。

Typically what you would do is the following通常你会做的是以下

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'
    )

I think this what you need since you don't seem to have any additional columns required on the mapping table in the many-many relationship.我认为这是您所需要的,因为在多对多关系中的映射表上似乎不需要任何其他列。 However, if you did you would need to use the Association Object pattern which is what you are doing originally.但是,如果您这样做了,则需要使用您最初正在做的 Association Object 模式。 In this case在这种情况下

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")

Note that in this case what you'll get in your relationship lists for State and Geo will actually be GeoState objects.请注意,在这种情况下,您将在StateGeo的关系列表中获得的内容实际上是GeoState对象。 If you want to use the Association Object pattern but have the relationship lists be populated by their respective counterpart objects instead.如果您想使用关联 Object 模式,但让关系列表由它们各自的对应对象填充。 You can use the AssociationProxy sqlalchemy extension which you can find the documentation for here您可以使用 AssociationProxy sqlalchemy 扩展,您可以在此处找到文档

For your reference,供你参考,

The Association Object pattern is documented here 此处记录了关联 Object 模式

Basic Many to Many pattern is documented here 此处记录了基本的多对多模式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM