2

Sqlalchemy はすべての変更を追跡し、これを行うとデータベースにコミットします。

b =  this_session.query(BaseUrl).filter_by(id=value).first()
b.basevalue = "new_value" #changing 
this_session.commit()     #commit the change to the DB

それはうまくいきます。

ただし、これを使用すると:

proxy =  this_session.execute("select * from base_url where id = {0}".format(value))
b = create_base_url(proxy) #create an instance of BaseUrl from proxy!
b.basevalue = "new_value"  #changing 
this_session.commit()      #it does NOT commit the change to the DB

もちろん、問題create_base_url()。この関数では、BaseUrlから取得したさまざまな引数を渡して のインスタンスを作成し、proxyそれを返すだけです。this_sessionオブジェクトのすべての変更を追跡するために、他に何もしません。次のような機能が必要です。

this_session.attach(b) #keep track of changes in b

のすべての変更を追跡するためbです。

そのような機能をどのように実装すればよいですか? 私が反対を持っていればそれも良いでしょう:

this_session.detach(b) #don't keep track of changes in b

と を使用postgresql 9.2してsqlalchemy 0.9.0います。

いくつかのヘルプに加えて、ドキュメント (この問題を扱っているセクション) へのリンクがあれば、詳細を読むことができます。:-)

4

1 に答える 1

5

SQLAlchemy のネイティブ ドキュメントを読む必要があるようです。非常によく書かれており、多くの問題、特にそのような基本的な問題に役立ちます。ORM を使用する場合、絶対に読んでおくべきものが 2 つあります。

SQLAlchemy に入る前にこれらを読む必要があります。

あなたの問題に対処する前に、次のことを行います。

proxy =  this_session.execute("select * from base_url where id = {0}".format(value))

決して、決して、これをしないでください!これにより、SQL インジェクション攻撃に対して脆弱になり、特に ORM がそれを処理してくれる可能性がある場合は、そうしたくないでしょう。代わりに、それを処理する方法がいくつかあります。最も簡単な方法は、Session.executeについて説明されているように、バインドされたパラメーターを使用することです。

proxy =  this_session.execute("select * from base_url where id = :value", {"value": value})

SQLAlchemy コアを直接使用して、nice ステートメントを作成することもできます。そのために、優れたSQL Expression Language Tutorialも読みたいと思うかもしれません。

そして今、あなたの実際の問題に:

this_session.add(b)

これはあなたが望んでいたものですattach: オブジェクトはセッション (およびデータベース) に追加されます。削除には 2 つの方法があります。データベースから削除する場合:

this_session.delete(b)

セッションから切り離したいだけの場合:

this_session.expunge(b)

ただし、通常、新しいセッションに再度追加する場合を除いて、セッションからそれらを削除することはありません。通常のユースケースでは、これを知る必要はありませんが、非常によく文書化されているため、簡単に読むことができます。

SQL インジェクション(またはバインドされたパラメーターが重要な理由) について:

問題を簡単に説明します。より広範な説明については、リソースがたくさんあるので自分で検索してください。

問題:何valueにでも設定できると想像してください。次のように、リテラル SQL ステートメントに設定することもできます。

value = "0 UNION SELECT * FROM admin_table"

これを実行すると、以下が生成されます。

"select * from base_url where id = 0 UNION SELECT * FROM admin_table"

ここで例を挙げただけですが、このテーブルに管理者の資格情報が含まれていると想像してください。あなたができることはもっとたくさんありますが、それはすべて悪いことです。しかし、ここで、バインドされたパラメーターがどのようにそれを行うかを見てみましょう:

"select * from base_url where id = '0 UNION SELECT * FROM admin_table'"

ほら、それは引用されます。はい、引用することもできますが、これはそれを処理します (興味がある場合は読んでください。それ以外の場合は、この方法で行ってください)。

Session.add で:

そうです、既に存在するオブジェクトを作成した場合 (なぜそれを行うのでしょうか?)、SQLAlchemy はそれを追加しようとします (既存のものを作成したことを認識していないため、クエリによってそれを取得すると想定しているため)。したがって、これが実際に使用するケースである場合は、Session.mergeおそらく役立つか、オブジェクトの状態を操作する必要があります (つまり、「一時的ではない」ようにします)。しかし、そうする前に、上記のリンク先のドキュメントを読んでください。なぜなら、私が説明したすべてのこと (およびそれ以上のこと) が、はるかに優れた方法で説明されているからです。

于 2013-09-05T12:07:10.200 に答える