На самом деле, "items.first (). Count" будет работать, так как возвращаемый вами кортеж является именованным кортежем ... но, думаю, вы не хотите видеть items.first (). Item.foo.
Второй способ, которым вы могли бы сделать это, - просто запустить результат вашего запроса () через функцию, которая создает желаемый результат:
def process(q):
for item, count in q:
item.count = count
yield count
edit: Вот обобщенная версия:
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)
Третье, вы изменяете класс 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.