2012-04-16 50 views
3

我正在寻找一种方法来告诉sqlalchemy将一些标签上的复杂查询映射到自定义类MyResult而不是默认的RowProxy类。这里有一个简单的工作示例如何将查询结果映射到sqlalchemy中的自定义对象?

''' 
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

这个例子不是很复杂,是真实的世界问题复杂吗?但最重要的是:这两个表之间的“现实生活”关系是什么:a)它实际上是表之间的“1-1关系”,两个组合的行代表一个“对象”实例(a-la继承); b)单Foo可以被5个Bars('1-n relationship')引用。在这种情况下,您的映射将不起作用,因为“id”列(用作PK)可能不是唯一的。 x)是仅这些视图还是希望能够通过创建并保存新的MyResult实例来添加新的数据库行? – van 2012-04-17 09:55:34

+1

真实世界的例子是连接4个表格。 1-n关系从雪片模式。我知道id问题,但可以通过连接的唯一ID或其他方式解决它。保存实例不是必需的。 – 2012-04-19 12:34:41

回答

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 
+1

您也可以创建一个“声明式”基类,然后将“MyResult”作为它的一个子类。许多人更喜欢声明风格,但它确实有权衡。 http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative.html – wberry 2012-04-16 21:54:17

4

。从您的样品中可以看出,将有超过1美孚返回Foo.id = 0,这将导致主键重复的值,这将反过来只会导致返回结果集的子集。在这种情况下,您可能应该将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也很重要,因为它们必须与您的类的列定义完全匹配(无论如何,构造函数将使用而不是)。

相关问题