0

views.py

def add_post(topic, request):
    post_form = PostForm(request.POST)
    if 'submit' in request.POST and post_form.validate():
        post = Post(body=post_form.body.data)
        post.user = request.user
        post.topic = topic
        DBSession.add(post)
        request.session.flash(_('Post was added'))
        transaction.commit()
        raise HTTPFound(location=request.route_url('topic',id=topic.id))
    return {'post_form':post_form}

models.py

class Topic(Base):
    __tablename__ = 'topics'
    id = Column(Integer, primary_key=True)
    ...
    post_count = Column(Integer, default=0)
    posts = relationship('Post', primaryjoin="Post.topic_id==Topic.id", backref='topic', lazy='dynamic')


class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    ...
    topic_id = Column(Integer, ForeignKey('topics.id'))


def post_inserted(mapper, conn, post):
    topic = post.topic
    topic.post_count = topic.posts.count()

event.listen(Post, "after_insert", post_inserted)

PyramidアプリでSQLAchemyイベント'after_insert'を使用して、それに属する投稿の数でトピックモデルを更新したいと思います。しかし、私は例外を取得します:

Traceback (most recent call last):
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/waitress/channel.py", line 329, in service
    task.service()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/waitress/task.py", line 173, in service
    self.execute()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/waitress/task.py", line 380, in execute
    app_iter = self.channel.server.application(env, start_response)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/pyramid/router.py", line 251, in __call__
    response = self.invoke_subrequest(request, use_tweens=True)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/pyramid/router.py", line 227, in invoke_subrequest
    response = handle_request(request)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/pyramid_tm/__init__.py", line 107, in tm_tween
    return response
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_manager.py", line 116, in __exit__
    self.commit()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_manager.py", line 107, in commit
    return self.get().commit()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_transaction.py", line 354, in commit
    reraise(t, v, tb)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_transaction.py", line 345, in commit
    self._commitResources()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_transaction.py", line 493, in _commitResources
    reraise(t, v, tb)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/transaction/_transaction.py", line 465, in _commitResources
    rm.tpc_begin(self)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/zope/sqlalchemy/datamanager.py", line 86, in tpc_begin
    self.session.flush()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/session.py", line 1583, in flush
    self._flush(objects)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/session.py", line 1654, in _flush
    flush_context.execute()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/unitofwork.py", line 331, in execute
    rec.execute(self)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/unitofwork.py", line 475, in execute
    uow
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/persistence.py", line 67, in save_obj
    states_to_insert, states_to_update)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/persistence.py", line 702, in _finalize_insert_update_commands
    mapper.dispatch.after_insert(mapper, connection, state)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/event.py", line 291, in __call__
    fn(*args, **kw)
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/events.py", line 360, in wrap
    wrapped_fn(*arg, **kw)
  File "/home/user/workspace/myforum/cube_forum/models.py", line 165, in post_saved
    topic.post_count = topic.posts.count()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/dynamic.py", line 249, in count
    sess = self.__session()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/dynamic.py", line 219, in __session
    sess.flush()
  File "/home/user/workspace/myforum/env/lib/python2.6/site-packages/sqlalchemy/orm/session.py", line 1577, in flush
    raise sa_exc.InvalidRequestError("Session is already flushing")
InvalidRequestError: Session is already flushing

Pyramid / SQLalchemyでそれを正しく行う方法は?

編集:質問は、実際にはPyramidでSQLAlchemyのイベントを使用する方法です。

4

2 に答える 2

1

SQLAlchemyイベント「after_insert」はこのタスクには適していません。

答えは、ここで説明されているPyramidのカスタムイベントを使用することですhttp://dannynavarro.net/2011/06/12/using-custom-events-in-pyramid/

于 2013-02-10T14:44:03.077 に答える
0

データベースレベルで問題があることがわかります。有効な投稿数の値を取得する保証はありません。複数のトランザクション内で同時に2つ以上の投稿がトピックに追加された場合を想像してください。新しい投稿を追加するたびにトピックテーブルをロックするか記録しない限り、関連付けられた投稿の有効な数を確認する方法はありません。

可能な解決策:

1)トピッククラスにメソッドを追加します。常に有効な数値ですが、毎回dbへのクエリを実行します。

class Topic(Base):
    ...
    def posts_count(self):
        return self.posts.count()

2)トピックに投稿を追加し、after_insertイベントを使用せずにコードのpost_countを更新します。投稿のトピックを変更するたびに、topic.post_countを更新する必要があります。また、この方法では、複数の投稿が同時にトピックに追加されたときに説明した問題は解決されません。

def add_post(topic, request):
    post_form = PostForm(request.POST)
    if 'submit' in request.POST and post_form.validate():
        post = Post(body=post_form.body.data)
        post.user = request.user

        topic.posts.append(post)
        topic.post_count = topic.posts.count()

        DBSession.add(post)
        DBSession.add(topic)

        request.session.flash(_('Post was added'))
        transaction.commit()
        raise HTTPFound(location=request.route_url('topic',id=topic.id))
    return {'post_form':post_form}
于 2013-02-08T22:49:40.970 に答える