2012-04-16 9 views
3

私はいくつかのタブで複雑なクエリをデフォルトのRowProxyクラスの代わりにカスタムクラスMyResultにマッピングするようにsqlalchemyに指示する方法を探しています。今、私はMyResultに結果行からマッピングを実行するためにSQLAlchemyのを指示する方法を探していますクエリの結果をsqlalchemyのカスタムオブジェクトにマップする方法は?

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() 

:ここでは簡単な作業例

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

し、次のコードです。

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

例は実際には複雑ではありませんが、現実世界の問題は複雑ですか?しかし、これらの2つのテーブルの間には「実際の」関係があります。a)テーブル間には実際には「1-1の関係」があり、2つの結合された行は1つの「オブジェクト」インスタンス(a-la継承)を表します。 b)単一のFooはmay bar( '1-n relationship')によって参照されることができます。この場合、あなたのマッピングはうまくいかず、 'id'カラム(PKとして使われる)は一意ではないかもしれません。 x)はこれらのビューのみですか、新しい 'MyResult'インスタンスを作成して保存することで新しいDB行を追加できますか? – van

+1

現実世界の例は4つのテーブルにわたる結合です。スノーフレークスキーマからの1-n関係。私はIDの問題を認識していますが、結合された一意のIDまたは別の方法でそれを解決できます。インスタンスを保存する必要はありません。 –

答えて

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

4

あなたのサンプルからわかるように、1 fooはどれが順番になります、主キーの重複値になりますこれは、Foo.id = 0に返さよりも多く存在します結果セットのサブセットが返されるだけです。この場合、primary_keyを他のBar列にも拡張する必要があります(Bar.idを含めるか、一意の場合はBar.nameを使用します)。

次に、あなたは(Using Literal SQLに記載されているように)from_statementこれを達成するために使用することができます。

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は、クラスの列定義と正確に一致する必要があるため、重要です(コンストラクタはではなく、を使用します)。

関連する問題