Odoo 几乎为每种功能提供了每种类型的字段。通常,我们为字段定义一个类定义并将其包含在模型中。但是,在某些业务实例中,我们可能需要通过添加新字段从用户界面本身修改模型。在本博客中,让我们研究如何定义自定义字段在视图中的位置以及如何使用函数在模型中创建它。
为了创建字段,我们首先需要使用模型来定义该字段。
class CustomField(models.Model):
"""从用户界面创建新的自定义字段的模型"""
_name = 'custom.field'
_description = '自定义字段创建'
_inherit = 'ir.model.fields'
position_field = fields.Many2one('ir.model.fields', string='字段名称')
position = fields.Selection([('before', 'Before'),
('after', 'After')], string='Position',
required=True)
model_id = fields.Many2one('ir.model', string='Model', required=True,
index=True, ondelete='cascade',
help="此字段所属的模型")
ref_model_id = fields.Many2one('ir.model', string='Model', index=True)
field_selection = fields.Char(string="选择选项")
relation_field = fields.Many2one('ir.model.fields', string='Related Field')
ttype = fields.Selection(string="Field Type", related='field_type')
field_type = fields.Selection(selection='get_possible_field_types',
string='Field Type', required=True)
extra_features = fields.Boolean(string="显示额外属性")
groups = fields.Many2many('res.groups', 'dynamic_field_creation_id',
'field_id', 'group_id')
@api.model
def get_possible_field_types(self):
"""提供所有可用的字段类型,但“one2many”和“reference”字段除外。"""
field_list = sorted((key, key) for key in fields.MetaField.by_type)
field_list.remove(('one2many', 'one2many'))
field_list.remove(('reference', 'reference'))
返回 field_list
@api.onchange('field_type')
def onchange_field_type(self):
如果 self.field_type:
如果 self.field_type == 'binary':
返回 {'domain': {'widget': [('name', '=', 'image')]}}
elif self.field_type == 'many2many':
返回 {'domain': {
'widget': [('name', 'in', ['many2many_tags', 'binary'])]}}
elif self.field_type == 'selection':
返回 {
'domain':{
'widget': [('name', 'in', ['radio', 'priority'])]}}
elif self.field_type == 'float':
返回 {'domain': {'widget': [('name', '=', 'monetary')]}}
elif self.field_type == 'many2one':
返回 {'domain': {'widget': [('name', '=', 'selection')]}}
else:
返回 {'domain': {'widget': [('id', '=', False)]}}
返回 {'domain': {'widget': [('id', '=', False)]}}
通过继承 Odoo 中字段的基础模型“ir.model.fields”,可以创建自定义模型。因此,可以在自定义模型中使用“ir.model.fields”中的字段。
笔记:
我们必须在自定义模型中重新定义 groups 字段,因为 many2many 字段 dynamic.fields.groups 和 ir.model.fields.groups 使用相同的表和列,这就是我们会收到 500 错误的原因。
为了解决这个问题,我们必须在“res.groups”中定义与我们的自定义模型相关的自定义字段。
class ResGroups(models.Model): """继承模型 Res Group 以添加字段来从模型自定义字段中
获取关系""" _inherit = 'res.groups' dynamic_field_id = fields.Many2one('custom.fields')
我们必须在自定义模型中指定字段。
position_field:定义要显示的自定义字段。它与“ir.model.fields”相关,是多对一字段。我们可以使用“position_field”来定义自定义字段的视图。
position:定义自定义字段的位置。可选字段有两个值:Before 和 After。自定义字段可以在“position_field”中定位在“Before”或“After”。
model_id:正在定义自定义字段的模型的名称。
field_type:定义字段的类型。这是一个选择字段。在函数“get_possible_field_types”中,将返回选择值。该函数将返回除“one2many”和“reference”之外的所有字段类型。
ref_model_id:如果是关系字段,则用于定义自定义字段和自定义模型之间的关系。
现在让我们检查一下这个定制模型的视图是如何定义的。
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- 模型自定义字段的形式 -->
<record id='custom_field_view_form' model='ir.ui.view'>
<field name="name">custom.fields.view.form</field>
<field name="model">custom.field</field>
<field name="arch" type="xml">
<form string="自定义字段创建">
<sheet>
<group>
<group string="字段信息">
<field name="name"/>
<field name="field_description"/>
<field name="state" readonly="1"
groups="base.group_no_one"/>
<field name="model_id"
options='{"no_open": True, "no_create": True}'/>
<field name="field_type"/>
<field name="field_selection"
placeholder="[('blue', 'Blue'),('yellow', 'Yellow')]"
attrs="{'required': [('field_type','in',['selection','reference'])],
'readonly': [('field_type','not in',['selection','reference'])],
'invisible': [('field_type','not in',['selection','reference'])]}"/>
<field name="ref_model_id"
options='{"no_open": True, "no_create": True}'
attrs="{'required': [('field_type','in',['many2one','many2many'])],
'readonly': [('field_type','not in',['many2one','many2many'])],
'invisible': [('field_type','not in',['many2one','many2many'])]}"/>
<field name="required"/>
</group>
<group string="Position">
<field name="position_field"
options='{"no_open": True, "no_create": True}'/>
<field name="position"/>
</group>
</group>
<group string="额外属性">
<group>
<field name="extra_features"/>
</group>
<group attrs="{'invisible': [('extra_features', '=', False)]}">
<field name="help"/>
</group>
<group attrs="{'invisible': [('extra_features', '=', False)]}">
<field name="readonly"/>
<field name="store"/>
<field name="index"/>
<field name="copied"/>
</group>
</group>
</sheet>
<footer>
<button name="action_create_custom_field"
string="创建字段" type="object"
class="oe_highlight"/>
<button string="取消" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- 菜单创建自定义字段的操作 -->
<record id='action_custom_fields' model='ir.actions.act_window'>
<field name="name">创建自定义字段</field>
<field name="res_model">custom.field</field>
<field name="view_mode">form</field>
<field name="view_id" ref="custom_field_view_form"/>
<field name="target">new</field>
</record>
<!-- 创建字段的菜单项 -->
<menuitem
id="menu_custom_field"
name="创建字段"
parent="sale.sale_menu_root"
action="action_custom_fields"
serial="10"/>
</odoo>
现在,让我们为按钮“CREATE FIELD”创建功能来创建自定义字段。
def action_create_custom_field(self):
"""用于创建自定义字段的按钮操作"""
self.env['ir.model.fields'].sudo().create({'name': self.name,
'field_description': self.field_description,
'model_id': self.model_id.id,
'ttype': self.field_type,
'relation': self.ref_model_id.model,
'required': self.required,
'index': self.index,
'store': self.store,
'help': self.help,
'readonly': self.readonly,
'selection': self.field_selection,
'copied': self.copied,
})
inherit_id = self.env.ref('sale.view_order_form')
arch_base = _('<?xml version="1.0"?>'
'<data>'
'<field name="%s" position="%s">'
'<field name="%s"/>'
'</field>'
'</data>') % (
self.position_field.name, self.position, self.name)
self.env['ir.ui.view'].sudo().create(
{'name': 'sale.custom.field.%s' % self.name,
'type': 'form',
'model': 'sale.order',
'mode': 'extension',
'inherit_id': inherit_id.id,
'arch_base': arch_base,
'active': True})
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
“create”方法用于模型“ir.model.fields”内部生成此函数描述中的字段。“sale.view_order_form”是员工表单视图的外部id。在此特定视图中的“Payment Term.”字段之后,我们必须定义自定义字段“Custom Field”的视图。因此,我们将从“inherit_id”中获取视图记录的id。接下来,我们将使用“ir.ui.view”中的“create”函数创建一个继承视图“sale.view_order_form”的新视图
为了向销售订单表单视图添加自定义字段,我们可以单击创建按钮。
有时,需要从用户界面创建一些模型字段。在这种情况下,我们可以使用此方法在模型内创建自定义字段。