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 '以上是关于sqlalchemy 关系映射的主要内容,如果未能解决你的问题,请参考以下文章