如何在pyramid / sqlalchemy / pyramid_tm中捕获完整性错误

时间:2015-03-01 10:15:01

标签: python python-3.x sqlalchemy pyramid

我正在尝试创建一个表单来编辑用户帐户。 此代码适用于已存在的用户。

如您所见,我在try / catch之前输入了一个return语句。 当用户名已存在时,这将生成预期的完整性异常。

但是如果我将其注释掉并让它进入try / catch块,则不会产生异常,它只是重定向到HTTPFound而没有错误。 对冲洗的呼吁没有任何作用。

if form.validate():

        user.username = form.username.data

        if form.password.data != "":
            user.password = encrypt(form.password.data)

        user.is_active = form.is_active.data
        user.email = form.email.data
        user.groups = form.groups.data

        # if i return here i will get integrity error as expected
        #return HTTPFound(location=request.route_url('user_details', id=user.id))

        with transaction.manager as tx:
            try:
                request.sqldb.flush()
                # no exception is generated here
                return HTTPFound(location=request.route_url('user_details', id=user.id))
            except IntegrityError as e:
                tx.abort()
                if 'UNIQUE constraint failed: users.username' in str(e):
                    form.username.errors.append('Username already exists')
                else:
                    errors.append('Integrity Error')

修改 这是有效的代码 事务管理器部分甚至不需要:

        user.username = form.username.data

        if form.password.data != "":
            user.password = encrypt(form.password.data)

        user.is_active = form.is_active.data
        user.email = form.email.data
        user.groups = form.groups.data

        try:  
            request.sqldb.flush()  
            return HTTPFound(location=request.route_url('user_details', id=user.id))
        except IntegrityError as e:
            if '(IntegrityError) duplicate key value' in str(e):
                errors.append('Username already exists')
            else:
                errors.append('Integrity Error')

            request.sqldb.rollback()

2 个答案:

答案 0 :(得分:0)

您需要获取模型,并对事务管理器中的模型对象进行更改,否则会话flush()的范围有限。 SQLAlchemy足够聪明,可以尝试仅刷新上下文管理器中发生的更改子集。因此:

with transaction.manager as tx:
    try:
        user = .... # get the user
        user.username = form.username.data

        if form.password.data != "":
            user.password = encrypt(form.password.data)

        user.is_active = form.is_active.data
        user.email = form.email.data
        user.groups = form.groups.data

        request.sqldb.flush()
        # no exception is generated here
        return HTTPFound(location=request.route_url('user_details', id=user.id))
    except IntegrityError as e:
        tx.abort()
        if 'UNIQUE constraint failed: users.username' in str(e):
            form.username.errors.append('Username already exists')
        else:
            errors.append('Integrity Error')

答案 1 :(得分:0)

我的解决方案基于全局异常处理。

http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/pylons/exceptions.html

from pyramid.view as view
import sqlalchemy.exc

@view.view_config(context=sqlalchemy.exc.IntegrityError, renderer='json')
def integrity_error(exc, request):
    request.response.status_code = 400
    return {
        'error': exc.orig.args[1]
    }

@view.exception_view_config(sqlalchemy.exc.IntegrityError, renderer='json')
def integrity_error(exc, request):
    request.response.status_code = 400
    return {
        'error': exc.orig.args[1]
    }

差异在http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/views.html

中描述

通过这种方式,我可以从金字塔中获得RESTful Api。它很粗糙,但在快速原型设计中很有用,并且可以在路径中节省大量代码。