SQLAlchemy等同于Django的annotate()方法

mir*_*e2k 4 python django orm sqlalchemy

我正在SQLAlchemy中进行这样的连接:

 items = Item.query\
    .outerjoin((ItemInfo, ItemInfo.item_id==Item.id))
 items.add_columns(ItemInfo.count)
Run Code Online (Sandbox Code Playgroud)

这会导致SQLAlchemy返回元组:

 >>> items.first()
 (<Item ...>, 2)
Run Code Online (Sandbox Code Playgroud)

我更喜欢它,如果"count"值将作为项目的属性返回,即我想做:

 >>> items.first().count
 2
Run Code Online (Sandbox Code Playgroud)

这支持吗?

zzz*_*eek 6

实际上,"items.first().count"会起作用,因为你得到的元组是一个命名的元组......但猜测你不想看到items.first().item.foo.

第二种方法是通过一个构造所需结果的函数来运行query()的结果:

def process(q):
    for item, count in q:
        item.count = count
        yield count
Run Code Online (Sandbox Code Playgroud)

编辑: 这是一个通用版本:

from sqlalchemy.orm.query import Query

class AnnotateQuery(Query):
    _annotations = ()

    def annotate(self, key, expr):
        q = self.add_column(expr)
        q._annotations = self._annotations + (key, )
        return q

    def __iter__(self):
        if not self._annotations:
            return super(AnnotateQuery, self).__iter__()
        else:
            for row in super(AnnotateQuery, self):
                item, remaining = row[0], row[1:]
                for i, key in enumerate(self._annotations):
                    setattr(item, key, remaining[i])
                yield item


# session usage:

Session = sessionmaker(query_cls=AnnotateQuery)

# query usage:
q = Session.query(Item).outerjoin(...).annotate('count', Item.count)
Run Code Online (Sandbox Code Playgroud)

第三,是你改变了Item类来支持这个功能.您将使用column_property()选择子查询到您的类:http://www.sqlalchemy.org/docs/orm/mapper_config.html#sql-expressions-as-mapped-attributes.如果您希望将属性加载为条件,则可以使用deferred:http: //www.sqlalchemy.org/docs/orm/mapper_config.html#deferred-column-loading.