Odoo Module Development: Understanding Models, Views and Security Rules
Odoo's modular architecture is one of the main reasons businesses choose it as their ERP platform. Instead of modifying the entire system whenever a business needs new functionality, developers can create custom modules that extend existing Odoo applications or introduce completely new features.
Three components are especially important in Odoo module development:
- Models — define data and business logic
- Views — define how users interact with the data
- Security Rules — control who can access which records and operations
Understanding how these three components work together is essential for building secure, maintainable, and upgrade-friendly Odoo customizations.
What Is an Odoo Module?
An Odoo module is a structured package that adds functionality to an Odoo database.
A module can introduce:
- New business models
- New fields
- Forms and list views
- Menus and actions
- Business workflows
- Reports
- Automated processes
- Access rights
- Record rules
- Website features
- API integrations
- Custom frontend functionality
For example, a company may want a Customer Credit Approval feature that is not available in its standard Odoo configuration.
A custom module could introduce:
Customer Credit Approval
↓
Credit Review
↓
Manager Approval
↓
Approved / Rejected
The module could contain a new model, user interface, workflow logic, and security configuration.
The Three Core Components of an Odoo Module
At a high level:
Odoo Custom Module
│
┌───────────┼───────────┐
↓ ↓ ↓
Models Views Security
│ │ │
Data User UI Permissions
│ │ │
└───────────┼───────────┘
↓
Business Workflow
These components work together.
For example:
Model defines a Purchase Approval record.
View provides the form where users create and review the record.
Security determines which users can create, read, approve, or delete it.
1. Understanding Odoo Models
A model represents a business object in Odoo.
Examples of standard Odoo models include:
res.partner → Customers / Contacts sale.order → Sales Orders purchase.order → Purchase Orders stock.picking → Inventory Transfers account.move → Accounting Documents mrp.production → Manufacturing Orders
Custom modules can create their own models.
For example:
from odoo import models, fieldsclass CreditApproval(models.Model): _name = 'credit.approval' _description = 'Customer Credit Approval' name = fields.Char( string='Reference', required=True ) customer_id = fields.Many2one( 'res.partner', string='Customer', required=True ) amount = fields.Float( string='Credit Limit' ) state = fields.Selection( [ ('draft', 'Draft'), ('submitted', 'Submitted'), ('approved', 'Approved'), ('rejected', 'Rejected'), ], default='draft' )
This model creates the foundation for the business functionality.
What Does a Model Define?
A model can define:
Fields
Examples:
- Text
- Integer
- Float
- Boolean
- Date
- Datetime
- Selection
- Many2one
- One2many
- Many2many
Business Logic
Python methods can define what happens when users perform actions.
Relationships
Models can connect with other Odoo models.
Constraints
Developers can prevent invalid business data.
Computed Values
Fields can automatically calculate values based on other fields.
Common Odoo Field Types
Char
Used for short text.
name = fields.Char( string='Name')
Examples:
- Reference number
- Customer code
- Serial number
Text
Used for longer text.
notes = fields.Text( string='Notes')
Useful for:
- Internal notes
- Descriptions
- Comments
Integer
Used for whole numbers.
quantity = fields.Integer( string='Quantity')
Float
Used for decimal values.
amount = fields.Float( string='Amount')
Boolean
Used for true/false values.
is_approved = fields.Boolean( string='Approved')
Selection
Used when users need to select from predefined options.
state = fields.Selection( [ ('draft', 'Draft'), ('approved', 'Approved'), ('rejected', 'Rejected'), ], default='draft')
Relational Fields
Relationships are particularly important in Odoo because ERP processes involve many connected business objects.
Many2one
A record links to one record from another model.
customer_id = fields.Many2one( 'res.partner', string='Customer')
A credit approval can therefore be linked to one customer.
One2many
One record can contain multiple related records.
For example:
line_ids = fields.One2many( 'credit.approval.line', 'approval_id', string='Approval Lines')
This could represent multiple approval conditions associated with one approval request.
Many2many
Multiple records can be linked on both sides.
For example:
user_ids = fields.Many2many( 'res.users', string='Approvers')
This allows multiple users to be assigned.
2. Understanding Odoo Views
A model defines the data and logic, but users need an interface to interact with that data.
This is where views come in.
Odoo views determine how records are displayed and edited.
Common view types include:
- Form
- List
- Kanban
- Search
- Calendar
- Pivot
- Graph
- Activity
Form Views
A form view allows users to create and edit individual records.
Example:
<record id="view_credit_approval_form"
model="ir.ui.view">
<field name="name">
credit.approval.form
</field>
<field name="model">
credit.approval
</field>
<field name="arch"
type="xml">
<form>
<sheet>
<group>
<field name="name"/>
<field name="customer_id"/>
<field name="amount"/>
<field name="state"/>
</group>
</sheet>
</form>
</field>
</record>
The model determines what data exists.
The view determines how users see and interact with that data.
List Views
List views display multiple records.
For example:
<list>
<field name="name"/>
<field name="customer_id"/>
<field name="amount"/>
<field name="state"/>
</list>
A user could see:
| Reference | Customer | Credit Limit | Status |
|---|---|---|---|
| CA001 | ABC Ltd | ₹50,000 | Draft |
| CA002 | XYZ Pvt Ltd | ₹100,000 | Approved |
| CA003 | Global Traders | ₹75,000 | Rejected |
List views are particularly useful for:
- Sales orders
- Purchase orders
- Customers
- Inventory records
- Approval requests
- Tasks
Kanban Views
Kanban views display records as cards.
For example:
┌──────────────┐ │ Draft │ │ │ │ CA001 │ │ ABC Ltd │ └──────────────┘ ┌──────────────┐ │ Approved │ │ │ │ CA002 │ │ XYZ Pvt Ltd │ └──────────────┘
Kanban views are useful for workflows where records move between stages.
Examples include:
- CRM opportunities
- Projects
- Helpdesk tickets
- Approval workflows
Search Views
Search views help users find and filter records.
For example:
<search>
<field name="name"/>
<field name="customer_id"/>
<field name="state"/>
</search>
You can also create filters for common business requirements.
For example:
My Approvals Approved Pending Approval Rejected High Credit Limit
This makes large datasets easier to manage.
3. Actions and Menus
A model and view alone are not enough.
Users need a way to access the functionality.
An Odoo module commonly uses:
Menu → Action → View → Model
For example:
Sales ↓ Credit Approvals ↓ Credit Approval List ↓ Credit Approval Form
An action can connect the menu with the appropriate model and views.
Example:
<record id="action_credit_approval"
model="ir.actions.act_window">
<field name="name">
Credit Approvals
</field>
<field name="res_model">
credit.approval
</field>
<field name="view_mode">
list,form
</field>
</record>
4. Understanding Odoo Security
Security is one of the most important parts of module development.
A module should not only determine what users can see but also what they are allowed to do.
Odoo security generally involves several mechanisms:
- User groups
- Access Control Lists (ACLs)
- Record rules
- Field-level restrictions
These mechanisms operate at different levels.
Access Control Lists
Access Control Lists determine whether a user has permission to perform operations on a model.
The four main operations are:
| Permission | Meaning |
|---|---|
| Read | View records |
| Create | Create records |
| Write | Modify records |
| Delete | Delete records |
A typical ACL file is:
security/ir.model.access.csv
Example:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_credit_user,credit.approval.user,model_credit_approval,base.group_user,1,1,1,0
This could allow a user to:
- Read
- Create
- Modify
but not delete credit approval records.
Why ACLs Are Important
Imagine a company has two roles:
Sales User
Can:
- Create approval requests
- View their requests
- Modify draft requests
Cannot:
- Approve requests
- Delete approved requests
Sales Manager
Can:
- View requests
- Approve requests
- Reject requests
- Modify records
These permissions can be implemented using appropriate groups and access rights.
5. Understanding Record Rules
ACLs answer:
Can this user perform an operation on this model?
Record rules answer:
Which records can this user access?
This distinction is extremely important.
For example, suppose there are 1,000 credit approval records.
A salesperson may be allowed to read the credit.approval model but should only see their own requests.
A record rule can restrict access to records associated with the current user.
Conceptually:
Credit Approval Records
│
├── User A → Own Records
├── User B → Own Records
└── Manager → All Records
This provides much more granular security.
ACL vs Record Rules
A simple way to remember the difference:
ACL
What can the user do?
Record Rule
Which records can the user do it to?
For example:
ACL:
Salesperson can read credit approvals.
Record Rule:
Salesperson can only read credit approvals where they are the assigned salesperson.
Both mechanisms may work together.
6. User Groups
Security rules are often assigned to user groups.
For example:
Credit Approval User Credit Approval Manager Credit Approval Administrator
You can then configure different permissions for each group.
Example:
| Role | Read | Create | Write | Delete | Approve |
|---|---|---|---|---|---|
| User | ✓ | ✓ | ✓ | ✗ | ✗ |
| Manager | ✓ | ✓ | ✓ | ✗ | ✓ |
| Administrator | ✓ | ✓ | ✓ | ✓ | ✓ |
This provides a structured security hierarchy.
7. Combining Models, Views and Security
Now let's see how the three components work together.
Suppose a company wants a Purchase Approval Module.
Model
purchase.approval
It contains:
- Purchase Order
- Requester
- Amount
- Approver
- Status
- Approval Date
View
The form provides:
Purchase Order Requester Amount Approver Status [Submit] [Approve] [Reject]
Security
Purchase Users:
Create Read Write
Purchase Managers:
Create Read Write Approve Reject
The result is a complete business application.
8. Using Inheritance in Odoo
One of the biggest advantages of Odoo development is that existing functionality can be extended through inheritance.
Suppose you want to add a field to the standard Sales Order model.
You can use:
from odoo import models, fieldsclass SaleOrder(models.Model): _inherit = 'sale.order' customer_reference = fields.Char( string='Customer Reference' )
This extends the existing model instead of modifying Odoo's core source code.
View Inheritance
Views can also be inherited.
For example, a custom module could add a field to an existing Sales Order form.
Conceptually:
<record id="sale_order_form_inherit"
model="ir.ui.view">
<field name="model">
sale.order
</field>
<field name="inherit_id"
ref="sale.view_order_form"/>
<field name="arch"
type="xml">
<xpath expr="//field[@name='partner_id']"
position="after">
<field name="customer_reference"/>
</xpath>
</field>
</record>
This allows developers to extend standard Odoo interfaces without replacing the complete original view.
9. Business Logic Belongs in the Model
Views should primarily control the presentation and interaction of data.
Business logic should generally remain in Python models.
For example:
from odoo.exceptions import UserErrordef action_approve(self): for record in self: if not record.approver_id: raise UserError( 'An approver must be assigned.' ) record.state = 'approved'
The approval logic is therefore reusable from the user interface and other parts of the system.
10. Computed Fields
Odoo models can also contain calculated fields.
For example:
total_amount = fields.Float( compute='_compute_total_amount', store=True)
The calculation can then be implemented in Python.
Computed fields are useful for:
- Totals
- Margins
- Status calculations
- KPIs
- Derived values
Developers should carefully consider whether a computed field should be stored, especially when working with large datasets.
11. Constraints and Data Validation
Models can also enforce business rules.
For example, a company may not allow a negative credit limit.
A validation rule can prevent invalid data from being saved.
Conceptually:
Credit Limit < 0
↓
Validation Error
↓
Record Not Saved
This protects data quality at the model level instead of relying only on the user interface.
12. Security Should Not Depend on the View
A common mistake is assuming that hiding a button or field makes something secure.
For example:
<field name="credit_limit"
invisible="1"/>
This only affects the interface.
It does not automatically provide complete access control.
Security should be implemented using appropriate:
- Groups
- ACLs
- Record rules
- Field restrictions
A user should not be able to access restricted information simply because a button or field is hidden from the screen.
13. Be Careful With sudo()
Developers sometimes use:
self.env['credit.approval'].sudo()
to bypass access restrictions.
While sudo() has legitimate uses, it should not be used simply to make permission errors disappear.
Before using it, developers should ask:
Does this operation genuinely need elevated privileges?
If not, the correct solution may be to configure the appropriate security groups or record rules.
14. Recommended Module Structure
A typical module might look like:
credit_approval/
│
├── __init__.py
├── __manifest__.py
│
├── models/
│ ├── __init__.py
│ └── credit_approval.py
│
├── views/
│ ├── credit_approval_views.xml
│ └── menu.xml
│
├── security/
│ ├── ir.model.access.csv
│ └── security.xml
│
├── data/
│ └── data.xml
│
├── wizard/
│ ├── __init__.py
│ └── approval_wizard.py
│
└── tests/
├── __init__.py
└── test_credit_approval.py
Not every module requires every directory, but keeping a predictable structure makes development and maintenance easier.
15. The Role of __manifest__.py
Every module needs a manifest describing the module and its dependencies.
Example:
{ 'name': 'Customer Credit Approval', 'version': '1.0', 'depends': [ 'sale', ], 'category': 'Sales', 'data': [ 'security/security.xml', 'security/ir.model.access.csv', 'views/credit_approval_views.xml', 'views/menu.xml', ], 'installable': True,}
The order of data files can matter.
For example, security definitions should be available before records that depend on them.
Developers should also keep dependencies limited to the modules actually required.
16. Testing Models, Views and Security
A custom module should be tested from three perspectives.
Model Testing
Check:
- Record creation
- Field calculations
- Constraints
- Business logic
- Workflow transitions
View Testing
Check:
- Forms
- Lists
- Search
- Buttons
- Menus
- User experience
Security Testing
Test different users:
Sales User Sales Manager Administrator
Make sure each role can perform exactly the operations it is supposed to perform.
17. Common Development Mistakes
Modifying Odoo Core
Direct core modifications can make upgrades and maintenance more difficult.
Better: Use custom modules and inheritance.
Ignoring Record Rules
ACLs alone may not provide the required record-level restrictions.
Better: Combine ACLs and record rules when necessary.
Using sudo() Everywhere
This can bypass security unexpectedly.
Better: Use elevated access only when justified.
Putting Business Logic in Views
Complex logic becomes harder to maintain.
Better: Keep business logic in Python models.
Creating Huge Modules
Putting unrelated functionality into one module creates unnecessary dependencies.
Better: Keep modules focused and modular.
Testing Only as Administrator
Administrator access can hide security problems.
Better: Test with realistic user roles.
Hard-Coding Business Rules
Business rules often change.
Better: Make appropriate business parameters configurable.
Models + Views + Security: The Complete Picture
The relationship can be summarized as:
ODOO MODULE
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
MODELS VIEWS SECURITY
│ │ │
Data & User Access &
Logic Interface Rules
│ │ │
└────────────┼────────────┘
▼
Business Workflow
│
▼
Business Users
A successful Odoo module needs all three layers to work together.
Best Practices Checklist
Before deploying a custom Odoo module, check:
- Requirement is clearly documented
- Standard Odoo functionality has been evaluated
- Models are logically designed
- Field relationships are appropriate
- Business logic is implemented in Python
- Views are clean and maintainable
- Model inheritance is used where appropriate
- View inheritance is used where appropriate
- ACLs are configured
- Record rules are reviewed
- User groups are correctly defined
- Sensitive fields are properly protected
- sudo() is used only when necessary
- Automated tests are included
- Different user roles have been tested
- Dependencies are minimized
- Module documentation is available
- Git version control is used
- Changes are tested in staging before production
How ERP Harbor Can Help With Odoo Module Development
Custom Odoo development requires more than adding fields and buttons. The solution should fit the business process while remaining secure, maintainable, and upgrade-friendly.
ERP Harbor Consulting Services provides Odoo development services including:
- Custom Odoo module development
- Python development
- Odoo model customization
- XML view development
- Security and access-rule configuration
- Workflow development
- Manufacturing customization
- Inventory customization
- Sales and Purchase customization
- Accounting customization
- API and third-party integrations
- Custom reports and dashboards
- Odoo migration and upgrades
- Testing and debugging
- Odoo support and maintenance
Our approach is to first understand the business requirement, evaluate standard Odoo functionality, and then develop custom functionality where it provides genuine value.
Conclusion
Models, Views, and Security Rules form the foundation of Odoo module development.
Models define the business data and logic. Views provide the interface through which users interact with that data. Security rules ensure that users can access only the records and operations appropriate to their roles.
When these three components are designed together, developers can create Odoo modules that are:
- Secure
- Scalable
- Maintainable
- User-friendly
- Upgrade-friendly
- Business-focused
Whether you're building a small approval workflow or a complete industry-specific Odoo application, understanding the relationship between models, views, and security is essential for creating reliable ERP customizations.