4

sqlalchemy 内でオブジェクトの主キーのハッシュを取得しようとしています。

class Userは次のようになります。

class User(base):
    __tablename__ == 'users'

    id = Column(Integer, primary_key=True)
    hash = Column(String(38), unique=True)

ユーザーを追加するには:

user = User()
session.add(user)
session.commit()

print user.id

主キーは . の後に割り当てられるため、ハッシュプロセスを ORM イベントにフックしようとしましたsession.flush()。ただし、フラッシュ中は、オブジェクトの状態への変更は永続化されません。

私にとって唯一の解決策はuser.id、最初のフラッシュの後に遅延ロードし、ハッシュ、割り当て、再度フラッシュして、最後にコミットすることです。

class User(base):
...

    @hybrid_property
    def hash(self):
        if not self.hash:
            self.hash = hash_function(self.id)
        return self.hash

これにより、次のことが可能になります。

user = User()
session.add(user)
hash = user.hash
session.commit()

sqlalchemy は、 and を開始し、UPDATEanduser.hashを永続化します。

しかし、これは悪いオプションのように思えます。たとえば、誰かがハッシュを割り当てるのを忘れた場合です (おそらく、オブジェクトの作成時にハッシュは必要ありません)。

別のオプションはありますか?自動的にハッシュされることを本当に望んでいますafter_insert。多分私は ORM イベントのドキュメントで何か不足していますか?

4

1 に答える 1

8

新たに生成された PK が一貫して利用可能になるのはこれが初めてなので、これは after_insert() に適した場所です (また、SELECT する必要はありませんが、「user.id の遅延読み込み」の意味がわかりません)。割り当てられる必要があります)、あなたがしようとしているのは、UPDATE ステートメントを直接発行することです。これが、マッパー レベルのフラッシュ イベントに (セッションではなく) 接続が与えられる理由です。

次のように簡単にする必要があります。

@event.listens_for(User, "after_insert")
def update_hash(mapper, connection, target):
    user_table = mapper.local_table
    connection.execute(
          user_table.update().
              values(hash=hash_function(target.id)).
              where(user_table.c.id==target.id)
    )

これを多くのユーザーにとってより効率的にしたい場合は、after_flush() イベントで行うことができます。

@event.listens_for(Session, "after_flush")
def update_hash(session, flush_context):
    hashes = [
        {"user_id":element.id, "hash":hash_function(element.id)}
        for element in session.new if isinstance(element, User)
    ]
    user_table = mapper.local_table
    session.execute(
          user_table.update().
              values(hash=bind('hash')).
              where(user_table.c.id==bind('user_id')),
          hashes
    )
于 2012-09-09T17:43:07.200 に答える