[FIX] fields: default to ondelete='cascade' for required m2o fields on transient
TransientModel (wizards) can be annoying because if they have required many2one fields, those fields will default to `ondelete='restrict'`, preventing user to delete the comodel records without deleting the transient model records first. To improve such case, we default to `ondelete='cascade'` for required many2one field on a TransientModel (unless specified otherwise) closes odoo/odoo#36738 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
committed by
Raphael Collet
parent
1a3dcfeae6
commit
c5fa4771fc
@@ -594,6 +594,14 @@ class RequiredM2O(models.Model):
|
||||
bar = fields.Many2one('res.country', required=True)
|
||||
|
||||
|
||||
class RequiredM2OTransient(models.TransientModel):
|
||||
_name = 'test_new_api.req_m2o_transient'
|
||||
_description = 'Transient Model with Required Many2one'
|
||||
|
||||
foo = fields.Many2one('res.currency', required=True, ondelete='restrict')
|
||||
bar = fields.Many2one('res.country', required=True)
|
||||
|
||||
|
||||
class Attachment(models.Model):
|
||||
_name = 'test_new_api.attachment'
|
||||
_description = 'Attachment'
|
||||
|
||||
@@ -1929,3 +1929,25 @@ class TestRequiredMany2one(common.TransactionCase):
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
field._setup_regular_base(Model)
|
||||
|
||||
|
||||
class TestRequiredMany2oneTransient(common.TransactionCase):
|
||||
|
||||
def test_explicit_ondelete(self):
|
||||
field = self.env['test_new_api.req_m2o_transient']._fields['foo']
|
||||
self.assertEqual(field.ondelete, 'restrict')
|
||||
|
||||
def test_implicit_ondelete(self):
|
||||
field = self.env['test_new_api.req_m2o_transient']._fields['bar']
|
||||
self.assertEqual(field.ondelete, 'cascade')
|
||||
|
||||
def test_explicit_set_null(self):
|
||||
Model = self.env['test_new_api.req_m2o_transient']
|
||||
field = Model._fields['foo']
|
||||
|
||||
# invalidate registry to redo the setup afterwards
|
||||
self.registry.registry_invalidated = True
|
||||
self.patch(field, 'ondelete', 'set null')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
field._setup_regular_base(Model)
|
||||
|
||||
+8
-6
@@ -2306,7 +2306,14 @@ class Many2one(_Relational):
|
||||
# 3) The ondelete attribute is explicitly defined as 'set null' for a required m2o,
|
||||
# this is considered a programming error.
|
||||
if not self.ondelete:
|
||||
self.ondelete = 'restrict' if self.required else 'set null'
|
||||
comodel = model.env[self.comodel_name]
|
||||
if model.is_transient() and not comodel.is_transient():
|
||||
# Many2one relations from TransientModel Model are annoying because
|
||||
# they can block deletion due to foreign keys. So unless stated
|
||||
# otherwise, we default them to ondelete='cascade'.
|
||||
self.ondelete = 'cascade' if self.required else 'set null'
|
||||
else:
|
||||
self.ondelete = 'restrict' if self.required else 'set null'
|
||||
if self.ondelete == 'set null' and self.required:
|
||||
raise ValueError(
|
||||
"The m2o field %s of model %s is required but declares its ondelete policy "
|
||||
@@ -2318,11 +2325,6 @@ class Many2one(_Relational):
|
||||
comodel = model.env[self.comodel_name]
|
||||
if not model.is_transient() and comodel.is_transient():
|
||||
raise ValueError('Many2one %s from Model to TransientModel is forbidden' % self)
|
||||
if model.is_transient() and not comodel.is_transient():
|
||||
# Many2one relations from TransientModel Model are annoying because
|
||||
# they can block deletion due to foreign keys. So unless stated
|
||||
# otherwise, we default them to ondelete='cascade'.
|
||||
self.ondelete = self.ondelete or 'cascade'
|
||||
return super(Many2one, self).update_db(model, columns)
|
||||
|
||||
def update_db_column(self, model, column):
|
||||
|
||||
Reference in New Issue
Block a user