【问题标题】:Pyramid / SQLAlchemy trouble with joined modelsPyramid / SQLAlchemy 与连接模型有关的问题
【发布时间】:2025-12-04 02:55:02
【问题描述】:

我对 Python 很陌生,对 Pyramid 也很陌生(这是我用 Python 编写的第一件事),但在数据库查询方面遇到了麻烦...

我有以下模型(无论如何都与我的问题相关):

  • MetadataRef(包含有关给定元数据类型的信息)
  • 元数据(包含实际元数据)- 这是 MetadataRef 的子项
  • 用户(包含用户)——这与元数据相关联。 MetadataRef.model = '用户' 和 metadata.model_id = user.id

我需要访问 MetadataRef 中的名称和 Metadata 中的值。

这是我的代码:

class User(Base):
    ...
    _meta = None

    def meta(self):
        if self._meta == None:
            self._meta = {}
            try:
                for item in DBSession.query(MetadataRef.key, Metadata.value).\
                    outerjoin(MetadataRef.meta).\
                    filter(
                        Metadata.model_id == self.id,
                        MetadataRef.model == 'User'
                    ):
                    self._meta[item.key] = item.value

            except DBAPIError:
                #@TODO: actually do something with this
                self._meta = {}
        return self._meta

SQLAlchemy 正在生成的查询确实返回了我需要的内容(无论如何都足够接近——它需要查询 model_id 作为 ON 子句的一部分而不是 WHERE,但这是次要的,我很确定我自己可以解决这个问题):

SELECT metadata_refs.`key` AS metadata_refs_key, metadata.value AS metadata_value 
FROM metadata_refs LEFT OUTER JOIN metadata ON metadata_refs.id = metadata.metadata_ref_id 
WHERE metadata.model_id = %s AND metadata_refs.model = %s

但是,当我访问对象时,我得到了这个错误:

AttributeError: 'KeyedTuple' object has no attribute 'metadata_value'

这使我认为我需要通过其他方式访问它,但我不知道如何。我试过.value.metadata_value.key 确实按预期工作。

有什么想法吗?

【问题讨论】:

    标签: python sqlalchemy pyramid


    【解决方案1】:

    您正在查询单独的属性(SA 文档中的“启用 ORM 的描述符”):

    DBSession.query(MetadataRef.key, Metadata.value)
    

    在这种情况下,查询返回的不是完整的 ORM 映射对象,而是 KeyedTuple,它是元组和属性对应于字段“标签”的对象之间的交叉。

    因此,访问数据的一种方法是通过其索引:

    ref_key = item[0]
    metadata_value = item[1]
    

    或者,要使 SA 为列使用特定名称,您可以使用Column.label() 方法:

    for item in DBSession.query(MetadataRef.key.label('ref_key'), Metadata.value.label('meta_value'))...
        self._meta[item.key] = item.meta_value
    

    对于调试,您可以使用Query.column_descriptions() 方法,它会告诉您查询返回的列的名称。

    【讨论】:

    • 哦,我没有意识到它必须通过数字索引来访问——我不喜欢依赖列顺序,以防我想在查询中添加其他任意列,所以你的替代解决方案是正是我要找的,谢谢!
    • 不必通过数字索引访问它 - 键控元组也允许通过 obj.attribute 语法访问 - 我的答案的后半部分解释了如何制作它工作。
    最近更新 更多