2013-02-08 80 views
0

views.py如何使用SQLAlchemy的事件金字塔

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) 

我想在我的金字塔的应用程序使用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 

如何在金字塔/ SQLalchemy正确吗?

编辑:问题实际上是如何在金字塔中使用SQLAlchemy的事件。

回答

0

我看到数据库级别存在问题 - 无法保证获得有效的帖子计数值。试想一下,如果在多个交易中同时向主题添加了两个或更多帖子 - 除非您每次添加新帖子时锁定主题表或记录,否则无法确定关联帖子的有效计数。

可能的解决方案:

1)将方法添加到Topic类。始终有效的号码,但每次都会执行到db的查询。

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

2)在您的代码中添加帖子并更新post_count,而不使用after_insert事件。每次更改帖子的主题时,都需要更新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} 
+0

首先是不可取的描述,因为我的目标是反规范化。我会尝试第二。 – bismigalis 2013-02-09 08:40:23

+0

这是工作(DBSession.add(后);实际上不需要DBSession.add(主题),在会话和帖子追加后的B/C主题),但我其实不想混乱我的看法与东西不与此相关的事件是专门为此设计的。 – bismigalis 2013-02-09 15:08:13