Create a Custom Model and Its View in Odoo
In this snippet, we will discuss how to create a custom model and its views in Odoo.
Models are used to represent the business data in Odoo. The models are defined in Python classes. Each model represents a table in the database. In order to create a model, we need to inherit our class from models.Model.
Views are used to define the user interface of the model. Views are defined in XML files. Each view represents a window or a page in the user interface.
Let’s take an example to understand how to create a custom model and its view in Odoo.

Model
from odoo import models, fields, api, _
class Payroll(models.Model):
_name = 'custom.payroll'
_description = 'Payroll'
name = fields.Char(string="Number", readonly=True, copy=False, default='New')
state = fields.Selection([
('draft', 'Draft'),
('verify', 'Waiting'),
('done', 'Done'),
('cancel', 'Rejected'),
], string='Status', index=True, readonly=True, copy=False, default='draft')
@api.model
def create(self, vals):
if vals.get('name', 'New') == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('salary.number') or 'New'
result = super(Payroll, self).create(vals)
return result
Views (views.xml)
<odoo>
<data>
<record id="custom_payroll_tree" model="ir.ui.view">
<field name="name">custom.payroll.tree</field>
<field name="model">custom.payroll</field>
<field name="arch" type="xml">
<tree string="Payrolls">
<field name="name"/>
</tree>
</field>
</record>
<record id="custom_payroll_form_view" model="ir.ui.view">
<field name="name">custom.payroll.form</field>
<field name="model">custom.payroll</field>
<field name="arch" type="xml">
<form string="Payroll">
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Salaray Sequence -->
<record id="sequence_salary_number" model="ir.sequence">
<field name="name">Salary Number</field>
<field name="code">salary.number</field>
<field name="active">TRUE</field>
<field name="prefix">SLIP/%(year)s/</field>
<field name="padding">5</field>
<field name="number_next">1</field>
<field name="number_increment">1</field>
</record>
<!-- we will add the Payroll module to Invoice menu items instead of creatign its own section -->
<record id="action_payrolls" model="ir.actions.act_window">
<field name="name">Payrolls</field>
<field name="res_model">custom.payroll</field>
<field name="view_mode">tree,form</field>
<field name="view_type">form</field>
<field name="target">inline</field>
<field name="view_id" ref="custom_payroll_tree"/>
</record>
<menuitem id="menu_payrolls_parent" name="Paryolls" parent="account.menu_finance" sequence="100"/>
<menuitem id="menu_payrolls" name="Paryolls" action="action_payrolls" parent="menu_payrolls_parent" sequence="0"/>
</data>
</odoo>
Security (ir.model.access.csv)
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink custom_payroll_manager,custom.payroll.manager,model_custom_payroll,base.group_user,1,1,1,1
Menu
Manifest
# -*- coding: utf-8 -*-
{
'name': "Custom Payroll",
'summary': """
Payroll
""",
'description': """
Payroll
""",
'author': "TLe Apps",
'website': "https://tleapps.com",
'category': 'Uncategorized',
'version': '1.0.0',
# any module necessary for this one to work correctly
'depends': ['base','account'],
# always loaded
'data': [
'security/ir.model.access.csv',
'views/views.xml',
],
'images': ['static/description/icon.png'],
}