我正在寻找一种方法来告诉sqlalchemy将一些标签上的复杂查询映射到自定义类MyResult
而不是默认的RowProxy
类。这是一个简单的工作示例
'''
create table foo(id integer, title text);
create table bar(id integer, foo_id integer, name text);
insert into foo values(0, 'null');
insert into foo values(1, 'eins');
insert into bar values(0,0, 'nullnull');
insert into bar values(1,0, 'einsnull');
insert into bar values(2,1, 'zweieins');
'''
和以下代码:
from sqlalchemy import *
from itertools import imap
db = create_engine('sqlite:///test.db')
metadata = MetaData(db)
class MyResult(object):
def __init__(self, id, title, name):
self.id = id
self.title = title
self.name = name
foo = Table('foo', metadata, autoload=True)
bar = Table('bar', metadata, autoload=True)
result = select([foo.c.id, foo.c.title, bar.c.name], foo.c.id == bar.c.foo_id).execute().fetchall()
现在我正在寻找一种方法来告诉sqlalchemy执行从结果行到MyResult的映射。
row = result[0]
print type(row)
#<class 'sqlalchemy.engine.base.RowProxy'>
print row.items()
#[(u'id', 0), (u'title', u'null'), (u'name', u'einsnull')]
我知道我可以手动进行映射,例如
my_result = imap(lambda x: MyResult(**x), result)
但我觉得这不是在sqlalchemy中处理它的方法。
答案 0 :(得分:6)
从您的示例中可以看出,Foo.id = 0
会返回超过1个Foo,这将导致主键的重复值,而这只会导致结果的一个子集 - 返回。在这种情况下,您可能应该将primary_key
也扩展到其他Bar
列(包括Bar.id
或使用Bar.name
(如果它是唯一的)。
然后您可以使用from_statement
(如Using Literal SQL中所述)来实现此目的:
sql_qry = select([foo.c.id.label("id"),
foo.c.title.label("title"),
bar.c.name.label("name")],
foo.c.id == bar.c.foo_id)
my_result_qry = session.query(MyResult).from_statement(sql_qry)
for x in my_result_qry.all():
print x
但是,必须映射模型MyResult
。您可以将其映射到一些虚拟(不存在)表或视图。列的label
也很重要,因为它们必须与类的列定义完全匹配(构造函数不仍然可以使用)。
答案 1 :(得分:3)
直接致电select
,您将遗漏ORM功能。您需要在MyResult
课程中使用mapper
。如你所知,MyResult
只是一个普通的类。
这样的事情:
Foo = mapper(MyResult, foo)
Bar = mapper(MyResult, bar) # NOTE: MyResult itself is unchanged by this
session = Session()
# query against the mapper class
result = session.query(Foo).filter(Foo.title == 'xyz').one()
print result.name