diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 809ac01a077..8a432240567 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1362,11 +1362,9 @@ class BaseModel(object): noupdate=noupdate, res_id=id, context=context)) cr.execute('RELEASE SAVEPOINT model_load_save') except psycopg2.Warning, e: - _logger.exception('Failed to import record %s', record) messages.append(dict(info, type='warning', message=str(e))) cr.execute('ROLLBACK TO SAVEPOINT model_load_save') except psycopg2.Error, e: - _logger.exception('Failed to import record %s', record) messages.append(dict( info, type='error', **PGERROR_TO_OE[e.pgcode](self, fg, info, e))) @@ -5327,11 +5325,28 @@ def convert_pgerror_23502(model, fields, info, e): 'message': message, 'field': field_name, } +def convert_pgerror_23505(model, fields, info, e): + m = re.match(r'^duplicate key (?P\w+) violates unique constraint', + str(e)) + field_name = m.group('field') + if not m or field_name not in fields: + return {'message': unicode(e)} + message = _(u"The value for the field '%s' already exists.") % field_name + field = fields.get(field_name) + if field: + message = _(u"%s This might be '%s' in the current model, or a field " + u"of the same name in an o2m.") % (message, field['string']) + return { + 'message': message, + 'field': field_name, + } PGERROR_TO_OE = collections.defaultdict( # shape of mapped converters lambda: (lambda model, fvg, info, pgerror: {'message': unicode(pgerror)}), { # not_null_violation '23502': convert_pgerror_23502, + # unique constraint error + '23505': convert_pgerror_23505, }) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tests/addons/test_impex/ir.model.access.csv b/openerp/tests/addons/test_impex/ir.model.access.csv index 9a674d9ee1f..fd0f7370c67 100644 --- a/openerp/tests/addons/test_impex/ir.model.access.csv +++ b/openerp/tests/addons/test_impex/ir.model.access.csv @@ -23,3 +23,4 @@ access_export_one2many_child_2,access_export_one2many_child_2,model_export_one2m access_export_many2many_other,access_export_many2many_other,model_export_many2many_other,,1,1,1,1 access_export_selection_withdefault,access_export_selection_withdefault,model_export_selection_withdefault,,1,1,1,1 access_export_one2many_recursive,access_export_one2many_recursive,model_export_one2many_recursive,,1,1,1,1 +access_export_unique,access_export_unique,model_export_unique,,1,1,1,1 diff --git a/openerp/tests/addons/test_impex/models.py b/openerp/tests/addons/test_impex/models.py index 95a7f90bda8..8c76850d628 100644 --- a/openerp/tests/addons/test_impex/models.py +++ b/openerp/tests/addons/test_impex/models.py @@ -144,3 +144,13 @@ class RecO2M(orm.Model): 'value': fields.integer(), 'child': fields.one2many('export.one2many.multiple', 'parent_id') } + +class OnlyOne(orm.Model): + _name = 'export.unique' + + _columns = { + 'value': fields.integer(), + } + _sql_constraints = [ + ('value_unique', 'unique (value)', "The value must be unique"), + ] diff --git a/openerp/tests/addons/test_impex/tests/test_load.py b/openerp/tests/addons/test_impex/tests/test_load.py index fe01a267d58..0afbf6f49c3 100644 --- a/openerp/tests/addons/test_impex/tests/test_load.py +++ b/openerp/tests/addons/test_impex/tests/test_load.py @@ -1149,3 +1149,29 @@ class test_datetime(ImporterCase): self.assertEqual( values(self.read(domain=[('id', 'in', result['ids'])])), ['2012-02-03 11:11:11']) + +class test_unique(ImporterCase): + model_name = 'export.unique' + + @mute_logger('openerp.sql_db') + def test_unique(self): + result = self.import_(['value'], [ + ['1'], + ['1'], + ['2'], + ['3'], + ['3'], + ]) + self.assertFalse(result['ids']) + self.assertEqual(result['messages'], [ + dict(message=u"The value for the field 'value' already exists. " + u"This might be 'unknown' in the current model, " + u"or a field of the same name in an o2m.", + type='error', rows={'from': 1, 'to': 1}, + record=1, field='value'), + dict(message=u"The value for the field 'value' already exists. " + u"This might be 'unknown' in the current model, " + u"or a field of the same name in an o2m.", + type='error', rows={'from': 4, 'to': 4}, + record=4, field='value'), + ])