[ADD] ir_model: add fields copy and related on ir.model.fields
Also add a constraint on the value of field `related`, and corresponding onchange methods.
This commit is contained in:
@@ -35,6 +35,8 @@ CREATE TABLE ir_model_fields (
|
||||
relation varchar,
|
||||
relation_field varchar,
|
||||
select_level varchar,
|
||||
copy boolean,
|
||||
related varchar,
|
||||
readonly boolean default False,
|
||||
required boolean default False,
|
||||
selectable boolean default False,
|
||||
|
||||
@@ -226,6 +226,8 @@ class ir_model_fields(osv.osv):
|
||||
'selection': fields.char('Selection Options', help="List of options for a selection field, "
|
||||
"specified as a Python expression defining a list of (key, label) pairs. "
|
||||
"For example: [('blue','Blue'),('yellow','Yellow')]"),
|
||||
'copy': fields.boolean('Copied', help="Whether the value is copied when duplicating a record."),
|
||||
'related': fields.char('Related Field', help="The corresponding related field, if any. This must be a dot-separated list of field names."),
|
||||
'required': fields.boolean('Required'),
|
||||
'readonly': fields.boolean('Readonly'),
|
||||
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search (deprecated)')],'Searchable', required=True),
|
||||
@@ -290,6 +292,40 @@ class ir_model_fields(osv.osv):
|
||||
('size_gt_zero', 'CHECK (size>=0)',_size_gt_zero_msg ),
|
||||
]
|
||||
|
||||
def _related_field(self):
|
||||
""" Return the ``Field`` instance corresponding to ``self.related``. """
|
||||
names = self.related.split(".")
|
||||
last = len(names) - 1
|
||||
model = self.env[self.model or self.model_id.model]
|
||||
for index, name in enumerate(names):
|
||||
field = model._fields.get(name)
|
||||
if field is None:
|
||||
raise UserError(_("Unknown field name '%s' in related field '%s'") % (name, self.related))
|
||||
if index < last and not field.relational:
|
||||
raise UserError(_("Non-relational field name '%s' in related field '%s'") % (name, self.related))
|
||||
model = model[name]
|
||||
return field
|
||||
|
||||
@api.one
|
||||
@api.constrains('related')
|
||||
def _check_related(self):
|
||||
if self.state == 'manual' and self.related:
|
||||
field = self._related_field()
|
||||
if field.type != self.ttype:
|
||||
raise UserError(_("Related field '%s' does not have type '%s'") % (self.related, self.ttype))
|
||||
if field.relational and field.comodel_name != self.relation:
|
||||
raise UserError(_("Related field '%s' does not have comodel '%s'") % (self.related, self.relation))
|
||||
|
||||
@api.onchange('related')
|
||||
def _onchange_related(self):
|
||||
if self.related:
|
||||
try:
|
||||
field = self._related_field()
|
||||
except UserError as e:
|
||||
return {'warning': {'title': _("Warning"), 'message': e.message}}
|
||||
self.ttype = field.type
|
||||
self.relation = field.comodel_name
|
||||
|
||||
@api.model
|
||||
def _custom_many2many_names(self, model_name, comodel_name):
|
||||
""" Return default names for the table and columns of a custom many2many field. """
|
||||
@@ -303,6 +339,7 @@ class ir_model_fields(osv.osv):
|
||||
|
||||
@api.onchange('ttype', 'model_id', 'relation')
|
||||
def _onchange_ttype(self):
|
||||
self.copy = (self.ttype != 'one2many')
|
||||
if self.ttype == 'many2many' and self.model_id and self.relation:
|
||||
names = self._custom_many2many_names(self.model_id.model, self.relation)
|
||||
self.relation_table, self.column1, self.column2 = names
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
</group>
|
||||
<group string="Properties">
|
||||
<group>
|
||||
<field name="related"/>
|
||||
<field name="ttype"/>
|
||||
<field name="relation" attrs="{'required': [('ttype','in',['many2one','one2many','many2many'])],'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/>
|
||||
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')], 'readonly': [('ttype','!=','one2many')]}"/>
|
||||
@@ -80,6 +81,7 @@
|
||||
<field name="required"/>
|
||||
<field name="readonly"/>
|
||||
<field name="select_level"/>
|
||||
<field name="copy"/>
|
||||
<field name="translate"/>
|
||||
<field name="on_delete" attrs="{'readonly': [('ttype','!=','many2one')]}"/>
|
||||
<field name="modules"/>
|
||||
@@ -170,6 +172,7 @@
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="related"/>
|
||||
<field name="ttype"/>
|
||||
<field name="relation" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],
|
||||
'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>
|
||||
@@ -187,6 +190,7 @@
|
||||
<field name="required"/>
|
||||
<field name="readonly"/>
|
||||
<field name="select_level"/>
|
||||
<field name="copy"/>
|
||||
<field name="translate"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
@@ -385,6 +385,8 @@ class BaseModel(object):
|
||||
'ttype': f.type,
|
||||
'relation': f.comodel_name or None,
|
||||
'select_level': tools.ustr(int(f.index)),
|
||||
'copy': bool(f.copy),
|
||||
'related': f.related and ".".join(f.related),
|
||||
'readonly': bool(f.readonly),
|
||||
'required': bool(f.required),
|
||||
'selectable': bool(f.search or f.store),
|
||||
@@ -670,6 +672,8 @@ class BaseModel(object):
|
||||
attrs = {
|
||||
'manual': True,
|
||||
'string': field['field_description'],
|
||||
'copy': bool(field['copy']),
|
||||
'related': field['related'],
|
||||
'required': bool(field['required']),
|
||||
'readonly': bool(field['readonly']),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user