简体   繁体   English

在Odoo ORM中处理SQL约束异常

[英]Handling SQL constraint exceptions in Odoo ORM

I've got a UNIQUE constraint defined in my model: 我的模型中定义了一个UNIQUE约束:

class FooBar(models.Model):
    _name = 'my.foobar'

    # ...

    _sql_constraints = [
        ('foo_bar_uniq', 'unique("foo", "bar")', 'You could not step twice into the same foobar!')
    ]

And a controller with code for creating new objects: 以及一个用于创建新对象的代码的控制器:

class FooBarController(http.Controller):
    @http.route('/foobar/create/', auth='public', website=True)
    def create(self, foo, bar):
        http.request.env['my.foobar'].create({
            'foo': foo,
            'bar': bar,
        })
        return http.request.render('my.thank_you_page')

If the UNIQUE constraint is violated I get an IntegrityError exception. 如果违反UNIQUE约束,我会收到IntegrityError异常。 I would like to catch it and display a different message to the user: 我想抓住它并向用户显示不同的消息:

from psycopg2 import IntegrityError

class FooBarController(http.Controller):
    @http.route('/foobar/create/', auth='public', website=True)
    def create(self, foo, bar):
        try:
            http.request.env['my.foobar'].create({
                'foo': foo,
                'bar': bar,
            })
            return http.request.render('my.thank_you_page')
        except IntegrityError:
            return http.request.render('my.error_page')

This works... kinda. 这有点......有点儿。 The IntegrityError is successfully caught, but all subsequent database operations (which, as far as I know, are trigger automatically by the website module) end in InternalError : 成功捕获了IntegrityError ,但所有后续数据库操作(据我所知,由website模块自动触发)以InternalError结束:

InternalError: current transaction is aborted, commands ignored until end of transaction block.

As a consequence, all that the end user sees is the Internal Server Error page. 因此,最终用户看到的所有内容都是“ Internal Server Error页面。

How can I handle UNIQUE constraint violations correctly? 如何正确处理UNIQUE约束违规?

在catch代码中要做的第一件事是提交或关闭数据库游标以释放锁。

Here is an example expanding on Emanuel's answer: 以下是扩展伊曼纽尔答案的例子:

class FooBarController(http.Controller):
    @http.route('/foobar/create/', auth='public', website=True)
    def create(self, foo, bar):
        try:
            http.request.env['my.foobar'].create({
                'foo': foo,
                'bar': bar,
            })
            return http.request.render('my.thank_you_page')
        except IntegrityError:
            # can't use the usual `http.request.env.cr` style,
            # because `env` queries db and everything explodes
            http.request._cr.rollback()
            return http.request.render('my.error_page')

You can use the cr.savepoint() context manager: 您可以使用cr.savepoint()上下文管理器:

class FooBarController(http.Controller):

    @http.route('/foobar/create/', auth='public', website=True)
    def create(self, foo, bar):
        try:
            with http.request.env.cr.savepoint():
                http.request.env['my.foobar'].create({
                    'foo': foo,
                    'bar': bar,
                })
                return http.request.render('my.thank_you_page')
        except IntegrityError:
            return http.request.render('my.error_page')

Any database calls inside the context manager will be run inside a PostgreSQL savepoint . 上下文管理器中的任何数据库调用都将在PostgreSQL保存点内运行。 If an exception occurs, the savepoint (not the transaction) will be rollbacked, so you will be able to make subsequent calls inside the current database transaction. 如果发生异常,将回滚保存点(而不是事务),因此您将能够在当前数据库事务中进行后续调用。

Additionally, if you do not want the IntegrityError s to be logged, you may temporarily mute the openerp.sql_db logger (or odoo.sql_db , if you are using Odoo 10 or above) using the mute_logger context manager/decorator: 此外,如果您不想记录IntegrityError ,则可以使用mute_logger上下文管理器/装饰器暂时将openerp.sql_db记录器(或odoo.sql_db ,如果您使用的是Odoo 10或更高版本) mute_logger

from openerp.tools import mute_logger

# ...

try:
    with mute_logger('openerp.sql_db'), http.request.env.cr.savepoint():
        # ...
except IntegrityError:
    # ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM