Enable Dark Mode!
By: Rahna Kabeer

How to Create & Manage a Custom Field From a Function in Odoo 16

Technical Odoo 16

Odoo includes nearly every kind of field for every kind of functionality. Typically, we define a class definition for a field and include it in the model. However, in some business instances, we might need to modify a model from the user interface itself by adding new fields. In this blog,  let's examine how to define a custom field's position in the view and how to create it inside a model using a function.

In order to create the field, we first need to define the field using a model.

class CustomField(models.Model):
"""Model for creating a new custom field from the user interface"""
   _name = 'custom.field'
   _description = 'Custom Field Creation'
   _inherit = 'ir.model.fields'
   position_field = fields.Many2one('ir.model.fields', string='Field Name')
   position = fields.Selection([('before', 'Before'),
                                ('after', 'After')], string='Position',
   model_id = fields.Many2one('ir.model', string='Model', required=True,
                              index=True, ondelete='cascade',
                              help="The model this field belongs to")
   ref_model_id = fields.Many2one('ir.model', string='Model', index=True)
   field_selection = fields.Char(string="Selection Options")
   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="Show Extra Properties")
   groups = fields.Many2many('res.groups', 'dynamic_field_creation_id',
                             'field_id', 'group_id')
   def get_possible_field_types(self):
"""Provide all field types that are available, with the exception of "one2many" and "reference" fields.."""
       field_list = sorted((key, key) for key in fields.MetaField.by_type)
       field_list.remove(('one2many', 'one2many'))
       field_list.remove(('reference', 'reference'))
       return field_list
   def onchange_field_type(self):
       if self.field_type:
           if self.field_type == 'binary':
               return {'domain': {'widget': [('name', '=', 'image')]}}
           elif self.field_type == 'many2many':
               return {'domain': {
                   'widget': [('name', 'in', ['many2many_tags', 'binary'])]}}
           elif self.field_type == 'selection':
               return {
                   'domain': {
                       'widget': [('name', 'in', ['radio', 'priority'])]}}
           elif self.field_type == 'float':
               return {'domain': {'widget': [('name', '=', 'monetary')]}}
           elif self.field_type == 'many2one':
               return {'domain': {'widget': [('name', '=', 'selection')]}}
               return {'domain': {'widget': [('id', '=', False)]}}
       return {'domain': {'widget': [('id', '=', False)]}}

By inheriting the base model for fields in Odoo, "ir.model.fields," a custom model is created. Thus, the fields in 'ir.model.fields' may be used in our custom model.


We have to redefine the groups field in our custom model since the many2many fields dynamic.fields.groups and ir.model.fields.groups use the same table and columns, which is why we would receive a 500 error.

We must define a custom field in "res.groups" in relation to our custom model in order to resolve this issue.

class ResGroups(models.Model):
"""Inherited the model Res Group for adding a field to get the relation
from the model custom fields"""
   _inherit = 'res.groups'
   dynamic_field_id = fields.Many2one('custom.fields')

We have to specify the fields in our custom model.

position_field: To define the custom field will be displayed. It is related to "ir.model.fields" and is a many-to-one field. We can use "position_field" to define the view of our custom field.

position: To define the custom field's location. The field for selection has two values: Before and After. The custom field can be positioned "Before" or "After" in the "position_field."

model_id: The name of the model for which the custom field is being defined.

field_type: To define the type of the field. It is a selection field. In the function "get_possible_field_types," the selection values are returned. All field types, except "one2many" and "reference," will be returned by the function.

ref_model_id: If it is a relational field, it is used to define the relationship between the custom field and the custom model.

Let's now examine how the view of this customized model is defined.

<?xml version="1.0" encoding="utf-8"?>
   <!-- Form of the model custom field -->
   <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="Custom Field Creation">
                       <group string="Field Info">
                           <field name="name"/>
                           <field name="field_description"/>
                           <field name="state" readonly="1"
                           <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 string="Position">
                           <field name="position_field"
                                  options='{"no_open": True, "no_create": True}'/>
                           <field name="position"/>
                   <group string="Extra Properties">
                           <field name="extra_features"/>
                       <group attrs="{'invisible': [('extra_features', '=', False)]}">
                           <field name="help"/>
                       <group attrs="{'invisible': [('extra_features', '=', False)]}">
                           <field name="readonly"/>
                           <field name="store"/>
                           <field name="index"/>
                           <field name="copied"/>
                   <button name="action_create_custom_field"
                           string="Create Field" type="object"
                   <button string="Cancel" class="oe_link" special="cancel"/>
   <!-- Action for the menu Create Custom Fields -->
   <record id='action_custom_fields' model='ir.actions.act_window'>
       <field name="name">Create Custom Fields</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>
   <!-- Menu Item for the Create Fields -->
       name="Create Fields"


Now, let’s create the function for the button ‘CREATE FIELD’ to create the custom field.

def action_create_custom_field(self):
"""Button action for creating custom field"""
   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"?>'
                 '<field name="%s" position="%s">'
                 '<field name="%s"/>'
                 '</data>') % (
                   self.position_field.name, self.position, self.name)
       {'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',

The "create" method is used inside the model "ir.model.fields" to generate fields inside this function description. "sale.view_order_form" is the external id of the employee form view. After the "Payment Term." field in this specific view, we must define the view of the custom field "Custom Field." Thus, we will get the view record's id from "inherit_id."Next, we will use the "create" function in "ir.ui.view" to create a new view that inherits the view "sale.view_order_form"


In order to add a custom field to the sale order form view, we may then click the create button.


Sometimes, it will be required to create some model fields from the user interface. In those circumstances, we can use this method to create a custom field inside a model. If you want to know more about How to Create & Manage a Custom Field From a Function in Odoo, Please refer to our previous blog.

If you need any assistance in odoo, we are online, please chat with us.


Leave a comment




Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635



Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.



Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message