sqlalchemy 关系映射

Posted

技术标签:

【中文标题】sqlalchemy 关系映射【英文标题】:sqlalchemy relational mapping 【发布时间】:2011-11-28 09:55:49 【问题描述】:

您好,我有一个简单的问题 - 我有 2 个表(地址和用户 - 用户有一个地址,很多用户可以住在同一个地址)...我创建了一个这样的 sqlalchemy 映射: 当我得到我的会话并尝试查询类似的东西时

    class Person(object):
'''
classdocs
'''
 idPerson = Column("idPerson", Integer, primary_key = True)
 name = Column("name", String)
 surname = Column("surname", String)
 idAddress = Column("idAddress", Integer, ForeignKey("pAddress.idAddress"))
 idState = Column("idState", Integer, ForeignKey("pState.idState"))
 Address = relationship(Address, primaryjoin=idAddress==Address.idAddress)

class Address(object):
'''
Class to represent table address object
'''
 idAddress = Column("idAddress", Integer, primary_key=True)
 street = Column("street", String)
 number = Column("number", Integer)
 postcode = Column("postcode", Integer)
 country = Column("country", String) 
 residents = relationship("Person",order_by="desc(Person.surname, Person.name)", primaryjoin="idAddress=Person.idPerson") 




    self.tablePerson = sqlalchemy.Table("pPerson", self.metadata, autoload=True)
    sqlalchemy.orm.mapper(Person, self.tablePerson)
    self.tableAddress = sqlalchemy.Table("pAddress", self.metadata, autoload=True)
    sqlalchemy.orm.mapper(Address, self.tableAddress) 


myaddress = session.query(Address).get(1);
print myaddress.residents[1].name

=> 我得到 TypeError: 'RelationshipProperty' 对象不支持索引

我知道居民是用来定义这种关系的,但是我怎么能得到给定地址分配给的居民名单呢?! 谢谢

【问题讨论】:

【参考方案1】:

您在错误的地方定义了关系。我认为您将Declarative Extension 与non-declarative 混合使用:

    当使用declarative 时,您在model 中定义您的关系。 否则,您在将model 映射到table 时定义它们

如果选项 2 是您正在执行的操作,那么您需要从 models 中删除两个 relationship 定义,并将其添加到映射器(只有一个就足够了):

mapper(Address, tableAddress,
properties='residents': relationship(Person, order_by=(desc(Person.name), desc(Person.surname)), backref="Address"),
) 

关于上面代码的更多内容:

    仅在一侧定义关系。 backref 关心对方。 您不需要指定primaryjoin(只要您指定了 ForeignKey,并且 SA 能够推断列) 您的order_by 配置不正确,请参阅上面的代码了解适用的版本。

【讨论】:

【参考方案2】:

您可以尝试在 Address 之后定义 Person,并使用指向 Address 的反向引用 - 这将创建数组元素:

class Address(object):
 __tablename__ = 'address_table'
 idAddress = Column("idAddress", Integer, primary_key=True)

class Person(object):
 idPerson = Column("idPerson", Integer, primary_key = True)
 ...
 address_id = Column(Integer, ForeignKey('address_table.idAddress'))
 address = relationship(Address, backref='residents')

然后就可以查询了:

myaddress = session.query(Address).get(1);
for residents in myaddress.residents:
  print name

此外,如果您在某个地址有很多居民,您可以使用 join 进一步过滤:

resultset = session.query(Address).join(Address.residents).filter(Person.name=='Joe')
# or
resultset = session.query(Person).filter(Person.name=='Joe').join(Person.address).filter(Address.state='NY')
and resultset.first() or resultset[0] or resultset.get(...) etc...

【讨论】:

好吧,我将这两个类放在单独的文件中。我有我的 db init 对象,它执行 ORM self.tableAddress = sqlalchemy.Table("pAddress", self.metadata, autoload=True) addressMapper = sqlalchemy.orm.mapper(Address, self.tableAddress) self.tablePerson = sqlalchemy.Table ("pPerson", self.metadata, autoload=True) personMapper = sqlalchemy.orm.mapper(Person, self.tablePerson) 在我按照你的建议做之后得到 AttributeError: 'Address' object has no attribute 'residents'。问题不是 autoload=True" 声明吗?我不认为 backref 被创建 我从未使用过 .Table()... 我的理解是,如果您要连接到 ORM 之外的表。 (如在您的班级中使用 Table() 或关系,但不能同时使用...)您可以检查 - sqlalchemy.org/docs/core/… 另外,对在单独文件中定义的表类使用 relationship() 是可以的……只要确保您的导入不是循环的,否则在第一次创建表时会导致问题。 看起来 mapper() 是为了支持经典映射:sqlalchemy.org/docs/orm/mapper_config.html,您可以使用声明式样式加入没有此的表:sqlalchemy.org/docs/orm/relationships.html#one-to-many ...根据我的经验,最后一个示例链接令人困惑,在 [one] 类上使用 backref 到 [many] 类似乎可以按照您的预期创建数组。 好吧,我试过了:class Person: pass Class Address: pass self.tableAddress = sqlalchemy.Table("pAddress", self.metadata, autoload=True) addressMapper = sqlalchemy.orm.mapper(Address , self.tableAddress) self.tablePerson = sqlalchemy.Table("pPerson", self.metadata, autoload=True) personMapper = sqlalchemy.orm.mapper(Person, self.tablePerson) 这只是简单地从数据库加载所有内容(它的那里)但现在我得到 sqlalchemy.exc.ArgumentError: Argument 'class_' is expected to be of type '', got '' 我不得不说休眠更好

以上是关于sqlalchemy 关系映射的主要内容,如果未能解决你的问题,请参考以下文章

一篇搞定SQLAlchemy--关系对象映射

SQLAlchemy 如何使用声明性映射一对一关系的单列

sqlalchemy一对一关系映射

SQLAlchemy - 将自引用关系映射为一对多(声明形式)

flask 中orm关系映射 sqlalchemy的查询

SQLAlchemy