Python 如何将查询结果映射到sqlalchemy中的自定义对象?

Python 如何将查询结果映射到sqlalchemy中的自定义对象?,python,sql,orm,sqlalchemy,Python,Sql,Orm,Sqlalchemy,我正在寻找一种方法,告诉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')

我正在寻找一种方法,告诉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')]

但是我觉得在sqlalchemy中这不是处理它的方法。

直接调用
select
,你就忽略了ORM特性。您需要在
MyResult
类中使用。正如您所看到的,
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

从您的示例中可以看出,对于
Foo.id=0
,将返回多个Foo,这将导致主键的值重复,而主键的值反过来只会返回结果集的一个子集。在这种情况下,您可能应该将
主键
扩展到其他
列(包括
Bar.id
或使用
Bar.name
,如果它是唯一的)

然后,您可以使用(如中所述)来实现这一点:

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
。您可以将其映射到某个虚拟(不存在)表或视图。此外,列的
标签
也很重要,因为它们必须与类的列定义完全匹配(构造函数无论如何都不会被使用)。

您还可以创建一个“声明性”基类,然后使
MyResult
成为它的子类。许多人更喜欢声明式风格,但它确实有取舍。这个例子并不复杂,现实世界的问题复杂吗?但最重要的是:这两个表之间的“真实”关系是什么:a)实际上是表之间的
1-1关系
,两个组合行表示一个“对象”实例(a-la继承);b) 单个Foo可由五月栏引用(
1-n关系
)。在这种情况下,映射将不起作用,因为
id
列(用作PK)可能不是唯一的。x) 这些是仅视图还是希望通过创建和保存新的
MyResult
实例来添加新的DB行?现实世界的示例是4个表的联接。雪花模式中的1-n关系。我知道id问题,但可以通过连接唯一id或其他方式解决它。不需要保存实例。
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