在我的CherryPy + Peewee应用程序中,我经常使用以下模式:启动事务,执行操作列表并返回显示结果的页面。如果在任何操作期间出现问题,我会在日志记录表中添加一行,然后重定向到显示该行的页面。
问题是CherryPy中的重定向是通过引发异常来执行的,异常会导致一些事务回滚。回滚是我失败的操作所需要的(以及所有以前的操作,即使它们成功了),但它不是我想要的日志记录。
例如,如果用户转到a_page?a=1&b=2&c=3
,则使用以下代码:
do_this
会找到x != y
而不会执行show_message
do_this
将更新Table1
do_that
会找到x == y
并执行show_message
show_message
会在Message
日志表show_message
会引发异常,以便重定向到显示刚刚记录的消息的页面由于在事务中异常上升,Table1
中do_this
的更新和show_message
中记录的消息都将被回滚。
如何提交日志记录表中的行并回滚所有其他更改?
@cherrypy.expose
def a_page(self, a, b, c):
with db.transaction():
self.do_this(a, b)
self.do_that(b, c)
return render('it_worked.html')
def do_this(self, x, y):
if x == y:
self.show_message('Wrong this')
Table1.update(f2=x).where(f1 == y).execute()
def do_that(self, x, y):
if x != y:
self.show_message('Wrong that')
Table1.update(f3=x).where(f1 == z).execute()
def show_message(self, message)
msg = Message.create(msg=message)
raise cherrypy.HTTPRedirect('show_message?id={}'.format(msg.id))
答案 0 :(得分:0)
这个解决方案似乎有效,但我不喜欢,因为它需要将事务传递给函数,因为它可能(不确定)不能用于嵌套事务。
import cherrypy
import peewee
db = peewee.SqliteDatabase('test.db', threadlocals=True)
class PeeweeModel(peewee.Model):
class Meta:
database = db
class Table1(PeeweeModel):
field1 = peewee.CharField()
Table1.drop_table(True)
Table1.create_table(True)
class Log(PeeweeModel):
msg = peewee.CharField()
@staticmethod
def show_log(msg, txn):
txn.rollback()
msg = Log.create(msg=msg)
txn.commit()
raise cherrypy.HTTPRedirect('show_log?msg_id={}'.format(msg.id))
Log.drop_table(True)
Log.create_table(True)
def table_content():
return '<br>'.join(['{} {}'.format(row.id, row.field1) for row in Table1.select()])
html = """<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<a href="index">index</a><br>
<a href="add_row">add_row</a><br>
{}<br>
Table1<br>
{}<br>
</body>
</html>"""
class App():
@cherrypy.expose
def index(self, msg='Hello'):
return html.format(msg, table_content())
@cherrypy.expose
def add_row(self):
with db.transaction() as txn:
Table1.update(field1=Table1.field1 + 1).execute()
Table1.update(field1=Table1.field1 + 1).where(Table1.id == 2).execute()
if Table1.select().count() == 5:
raise Log.show_log('Something went wrong', txn)
Table1.create(field1=1, field2=2)
return html.format('Added record to Table1', table_content())
@cherrypy.expose
def show_log(self, msg_id):
msg = Log.get(Log.id == msg_id)
text = 'Message id {}: {}'.format(msg.id, msg.msg)
return html.format(text, table_content())
cherrypy.quickstart(App(), '/')