flask-sqlalchemy两个表之间的多种关系类型

时间:2014-06-26 04:15:53

标签: python sqlalchemy relationship

我在两个模型之间设置多个关系时遇到问题。这些是我现在拥有的两个模型:

class Product(db.Model):
    tablename='product'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    image_id = db.Column(db.Integer, db.ForeignKey('image.id'))
    image = db.relationship('Image',uselist=False,backref=db.backref('product'))

class Image(db.Model):
    __tablename__='address'
    id = db.Column(db.Integer, primary_key=True)
    normal = db.Column(db.String(200))
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
    product = db.relationship('Product', backref='product_images')

产品应该与封面图像一对一,以及与其他图像库一对一的产品。但是,外键存在循环依赖。

我只想在两张表中这样做。还有另一种方法可以实现这两种关系吗?

此时代码抛出:

sqlalchemy.exc.AmbiguousForeignKeysError

1 个答案:

答案 0 :(得分:2)

这里有两个循环依赖:

  1. 外键相互依赖于每个表的存在。必须在依赖表已存在之后创建其中一个fks。在其中一个上设置use_alter=Truename='some_name即可解决此问题。
  2. 这两个关系都需要在插入后解析其目标的primary_key,但是相互依赖于已经提交的两者。将post_update=True设置为一个即可解决此问题。
  3. 请参阅以下文档:

    这是一个展示解决方案的工作示例。

    from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Table
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker, relationship
    
    engine = create_engine('sqlite:///:memory:', echo=True)
    Session = sessionmaker(bind=engine)
    session = Session()
    Base = declarative_base(bind=engine)
    
    
    class Product(Base):
        __tablename__ = 'product'
    
        id = Column(Integer, primary_key=True)
        name = Column(String, nullable=False)
    
        # cover image foreign key
        # use_alter=True along with name='' adds this foreign key after Image has been created to avoid circular dependency
        cover_id = Column(Integer, ForeignKey('image.id', use_alter=True, name='fk_product_cover_id'))
    
        # cover image one-to-one relationship
        # set post_update=True to avoid circular dependency during
        cover = relationship('Image', foreign_keys=cover_id, post_update=True)
    
    class Image(Base):
        __tablename__ = 'image'
    
        id = Column(Integer, primary_key=True)
        path = Column(String, nullable=False)
        product_id = Column(Integer, ForeignKey(Product.id))
    
        # product gallery many-to-one
        product = relationship(Product, foreign_keys=product_id, backref='images')
    
        # nothing special was need in Image, all circular dependencies were solved in Product
    
    
    Base.metadata.create_all()
    
    # create some images
    i1 = Image(path='img1')
    i2 = Image(path='img2')
    i3 = Image(path='img3')
    i4 = Image(path='img4')
    
    # create a product with those images, one of which will also be the cover
    p1 = Product(name='sample', images=[i1, i2, i3, i4], cover=i2)
    
    session.add(p1)
    session.commit()
    
    print 'cover:', p1.cover.path  # prints one cover image path
    print 'images:', [i.path for i in p1.images]  # prints 4 gallery image paths
    
    print 'image product:', p1.images[0].product.name  # prints product name from image perspective