简体   繁体   English

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

[英]flask-sqlalchemy multiple relationship types between two tables

I am having trouble setting up multiple relationships between two models. 我在两个模型之间建立多个关系时遇到问题。 These are my two models as I have them now: 这些是我现在拥有的两个型号:

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

Product should have a one-to-one with a cover image, and a one to many with a gallery of other images. 产品应该与封面图像一对一,以及与其他图像库一对一的产品。 However, there is a circular dependency with the foreign keys. 但是,外键存在循环依赖关系。

I would like to do this in only two tables. 我想只在两张表中这样做。 Is there another way to implement these two relationships? 还有另一种方法可以实现这两种关系吗?

At this point code above throws: 此时代码抛出:

sqlalchemy.exc.AmbiguousForeignKeysError

There are two circular dependencies here: 这里有两个循环依赖:

  1. The foreign keys are mutually dependent on the existence of each table. 外键相互依赖于每个表的存在。 One of the fks must be created after the dependent table already exists. 必须在依赖表已存在之后创建其中一个fks。 Set use_alter=True and name='some_name on one to resolve this. 在一个上设置use_alter=Truename='some_name以解决此问题。
  2. The relationships both need to resolve the primary_key of their target after insert, but are mutually dependent on both having already been commited. 这些关系都需要在插入后解析其目标的primary_key,但是相互依赖于已经提交的两者。 Set post_update=True on one to resolve this. 在一个上设置post_update=True以解决此问题。

See the following documentation: 请参阅以下文档:

Here is a working example demonstrating the solution. 这是一个展示解决方案的工作示例。

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

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

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