如何正确定义SQLAlchemy反向引用,以便可以反映出来?

时间:2018-10-22 16:49:19

标签: python python-3.x orm sqlalchemy

假设我们在某些Models.py文件中具有以下代码:

.vocabulary_

我们想使用自动映射库来反映这些模型,因此我们将这段代码存储在另一个名为Database.py的模块中:

class Person(db.Model):
    __tablename__ = 'Persons'
    ID = db.Column(db.Integer, primary_key=True, nullable=False)
    Name = db.Column(db.String(255), nullable=False)

class House(db.Model):
    __tablename__ = 'Houses'
    ID = db.Column(db.Integer,primary_key=True,nullable=False)
    OwnerID = db.Column(db.Integer, nullable=False)
    TenantID = db.Column(db.Integer, nullable=False)

    __table_args__ = (
        db.ForeignKeyConstraint(
            ['OwnerID'],
            ['Persons.ID'],
        ),
        db.ForeignKeyConstraint(
            ['TenantID'],
            ['Persons.ID'],
        ),
    )

    OwnerBackref = db.relationship('Person', backref='OwnerBackref', lazy=True, foreign_keys=[OwnerID])
    TenantBackref = db.relationship('Person', backref='TenantBackref', lazy=True, foreign_keys=[TenantID])

现在,当我在其他模块中导入House时,我希望能够做到这一点:

Base = automap_base()
engine = create_engine(DB_CONNECTION, pool_size=10, max_overflow=20)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base.prepare(engine, reflect=True)
Person = Base.classes.Persons
House = Base.classes.Houses

但是,我收到一条错误消息,说那2个反向引用不存在,而是将一个名为“ persons”的字段添加到了我的House对象,但是这里的问题是它只链接了1个(租户或所有者)。我的意思是,如果我这样做:

h = db_session.query(House).first()
print(h.OwnerBackref.Name)
print(h.TenantBackref.Name)

它将仅打印相应租户的姓名,或者为所有者打印姓名,而使我无法访问另一方的信息。 (请注意,这里没有设置我设置为反向引用的名称)

所以,我的问题是如何使用创建的后向引用访问所需的信息? 我在这里做错了吗?

1 个答案:

答案 0 :(得分:0)

代码中的错误是您正在使用foreign_keys=来定义表之间的关系,但是您正在将本地键名而不是外键名传递给该函数。对于您的代码,您不能使用foreign_keys=在House模型中定义关系,因为只有一个可能的外键Person.ID,但是有两个可能的本地键House.OwnerIDHouse.TenantID。应该使用primaryjoin=参数来指定它。

class Person(db.Model):
    __tablename__ = 'Persons'
    ID = db.Column(db.Integer, primary_key=True)
    Name = db.Column(db.String(255), nullable=False)

class House(db.Model):
    __tablename__ = 'Houses'
    ID = db.Column(db.Integer,primary_key=True)
    OwnerID = db.Column(db.Integer, db.ForeignKey('Persons.ID'), nullable=False)
    TenantID = db.Column(db.Integer, db.ForeignKey('Persons.ID'), nullable=False)

    Owner = db.relationship('Person', backref='HousesOwned', primaryjoin='House.OwnerID == Person.ID')
    Tenant = db.relationship('Person', backref='HousesOccupied', primaryjoin='House.TenantID == Person.ID')

如果将关系语句放置在Person模型而不是House模型中,则可以使用foreign_keys=primaryjoin=来定义关系。下面的代码将产生与前面的代码完全相同的关系。

class Person(db.Model):
    __tablename__ = 'Persons'
    ID = db.Column(db.Integer, primary_key=True)
    Name = db.Column(db.String(255), nullable=False)

    HousesOwned = db.relationship('House', backref='Owner', foreign_keys='[House.OwnerID]')
    HousesOccupied = db.relationship('House', backref='Tenant', foreign_keys='[House.TenantID]')


class House(db.Model):
    __tablename__ = 'Houses'
    ID = db.Column(db.Integer,primary_key=True)
    OwnerID = db.Column(db.Integer, db.ForeignKey('Persons.ID'), nullable=False)
    TenantID = db.Column(db.Integer, db.ForeignKey('Persons.ID'), nullable=False)