Launch offer
Business website $150 USD Custom plugin $200 USD Ready in 5 days
Get a quote
Odoo

Odoo Complete Tutorial (112 Topics with Modules, ORM, Views & Final Project)

Complete Odoo tutorial covering installation, custom modules, models, ORM, XML views, security, QWeb, APIs, business apps, and a final complete custom Odoo module.

This complete Odoo tutorial covers 112 topics — from installation and custom modules to ORM, views, security, QWeb, APIs, business apps, and a final complete custom Odoo module.

Course roadmap

1. Introduction to Odoo

Odoo is an open-source business application suite and development framework. This series covers Community setup, custom modules, models/fields, XML views, security, QWeb, website/portal, APIs, standard business apps, and a complete custom Odoo module as the final project.

  1. Set up Odoo and a custom addons path.
  2. Build models, views, and security.
  3. Ship the final custom Odoo module.

Learning path

Install + project structure
Modules, models, fields, ORM
Views, menus, actions, security
QWeb, website, reports, cron
JS/OWL + business apps
APIs, deploy, final custom module

2. What is Odoo?

Odoo ships apps (Sales, Accounting, Inventory, etc.) and lets developers extend them with modules.

Odoo at a glance

ERP + CRM + eCommerce apps
Python backend
PostgreSQL database
XML views + QWeb
Modular addons architecture

3. Odoo Features and Architecture

Requests hit the web layer; business logic lives in models; data sits in PostgreSQL.

Architecture layers

Web / RPC (JSON-RPC, XML-RPC)
ORM + models
PostgreSQL
Addons modules
Assets (JS/CSS/OWL)
QWeb templates & reports

4. Odoo Community vs Enterprise

Community covers core ERP development; Enterprise adds studio, extra apps, and support options.

Compare tip

Community → free, open modules
Enterprise → paid apps + features
Custom modules work on both (license-aware)
Pick edition by budget and required apps

5. Odoo Installation

Official docs recommend a system user, PostgreSQL, Python deps, and a service/systemd unit for production.

  1. Install PostgreSQL and Python dependencies.
  2. Configure odoo.conf.
  3. Start Odoo and create a database.

Install checklist

PostgreSQL running
Python venv + requirements
odoo-bin / odoo package
Config file (odoo.conf)
Create database from UI

6. Setting Up Odoo Development Environment

Use a dedicated addons folder for your custom modules outside core Odoo.

Dev tips

addons_path = core,enterprise?,custom
--dev=all for assets/xml reload
Log level info/debug
Git ignore filestore & sessions

7. Odoo Project Structure

Keep custom code in your own addons repo; never edit upstream modules directly.

Structure

odoo/
addons/ (core)
custom_addons/
  my_module/
odoo.conf
filestore/

8. Odoo Configuration

Never commit production admin passwords; use secrets and restricted file permissions.

odoo.conf sketch

[options]
admin_passwd = CHANGE_ME
db_host = localhost
db_user = odoo
db_password = odoo
addons_path = /opt/odoo/addons,/opt/odoo/custom_addons
http_port = 8069

9. Odoo Database Management

Backups include PostgreSQL dump plus filestore when attachments matter.

DB ops tip

Create DB from /web/database/manager
Backup before upgrades
Restore dump + filestore
Use separate DBs per project

10. Odoo User and Company Setup

Assign users to groups early; company settings drive accounting and documents.

Setup checklist

Company data & currency
Users + groups
Languages/timezone
Multi-company rules if needed

11. Odoo Apps and Modules

Activate Developer Mode to see technical names and update apps list.

Apps tip

Apps menu → Install
Update Apps List after adding modules
Upgrade module after code changes
Dependencies in manifest

12. Creating Your First Odoo Module

Add the module to addons_path, update apps list, then install it.

  1. Create module folder and manifest.
  2. Add a simple model + list/form view.
  3. Install from Apps.

Minimal module

my_library/
  __init__.py
  __manifest__.py
  models/
  views/
  security/

13. Odoo Module Structure

Import Python packages in __init__.py; load XML in manifest data/demo lists.

Typical folders

models/
views/
security/
data/
wizards/
controllers/
static/src/
report/

14. Odoo Manifest File

Version, depends, and data order matter for install/upgrade success.

Manifest sketch

{
    'name': 'My Library',
    'version': '1.0.0',
    'category': 'Services',
    'depends': ['base', 'mail'],
    'data': [
        'security/ir.model.access.csv',
        'views/book_views.xml',
    ],
    'installable': True,
    'application': True,
}

15. Models in Odoo

_name creates a new model; _inherit extends existing ones.

Model sketch

from odoo import models, fields

class LibraryBook(models.Model):
    _name = 'library.book'
    _description = 'Library Book'

    name = fields.Char(required=True)

16. Model Fields in Odoo

Field types map to PostgreSQL columns (or relations) and drive form widgets.

Field idea

Scalar fields (Char, Integer…)
Relational (Many2one…)
Computed / related
Attributes: required, index, tracking

17. Char, Text and Integer Fields in Odoo

Char supports size/translate; Text is unbounded multi-line content.

Examples

name = fields.Char(string='Title', required=True)
notes = fields.Text()
pages = fields.Integer()

18. Float and Monetary Fields in Odoo

Monetary fields pair with res.currency for correct display and rounding.

Monetary tip

currency_id = fields.Many2one('res.currency')
amount = fields.Monetary(currency_field='currency_id')

19. Boolean and Selection Fields in Odoo

Selection values are stored as keys; labels are for UI.

Selection

active = fields.Boolean(default=True)
state = fields.Selection([
    ('draft', 'Draft'),
    ('done', 'Done'),
], default='draft')

20. Date and Datetime Fields in Odoo

UI converts Datetime to user timezone; be careful in server-side comparisons.

Date fields

publish_date = fields.Date()
due_at = fields.Datetime()

21. Many2one Fields in Odoo

Use ondelete and domain to keep relations clean and filtered.

Many2one

partner_id = fields.Many2one('res.partner', string='Customer', ondelete='restrict')

22. One2many Fields in Odoo

One2many is virtual; the inverse Many2one stores the relation.

One2many

line_ids = fields.One2many('sale.order.line', 'order_id', string='Lines')

23. Many2many Fields in Odoo

Optional relation/column names customize the junction table.

Many2many

tag_ids = fields.Many2many('library.tag', string='Tags')

24. Computed Fields in Odoo

Set store=True when you need search/group on computed values.

Computed

total = fields.Float(compute='_compute_total', store=True)

@api.depends('line_ids.price')
def _compute_total(self):
    for rec in self:
        rec.total = sum(rec.line_ids.mapped('price'))

25. Related Fields in Odoo

Related fields can be stored; they still depend on the path staying valid.

Related

partner_email = fields.Char(related='partner_id.email', store=True)

26. Default Values in Odoo

Callables receive the model and can use env/context for dynamic defaults.

Default

state = fields.Selection(..., default='draft')
user_id = fields.Many2one('res.users', default=lambda self: self.env.user)

27. Field Constraints in Odoo

Combine SQL constraints with Python @api.constrains for business rules.

SQL constraint

_sql_constraints = [
    ('isbn_uniq', 'unique(isbn)', 'ISBN must be unique!'),
]

28. ORM in Odoo

Prefer ORM over raw SQL except for justified performance cases.

ORM idea

env['model.name']
create / search / browse
write / unlink
mapped / filtered / sorted

29. CRUD Operations in Odoo

Always check access rights; sudo() is for trusted system logic only.

CRUD overview

create(vals)
search(domain) / browse(ids)
write(vals)
unlink()

30. Create Records in Odoo

Override create to set defaults or related side effects carefully.

create

book = self.env['library.book'].create({
    'name': 'Odoo Guide',
    'pages': 200,
})

31. Search Records in Odoo

Use domains, limit/offset/order for efficient queries.

search

books = self.env['library.book'].search([
    ('active', '=', True),
], limit=20, order='name')

32. Update Records in Odoo

write applies to all records in the set — filter first when needed.

write

books.write({'state': 'done'})

33. Delete Records in Odoo

Prefer archiving (active=False) for business documents when audit matters.

unlink

books.unlink()

34. Recordsets in Odoo

Recordsets are the core ORM unit — methods usually operate on self as a set.

Recordset helpers

names = books.mapped('name')
active = books.filtered('active')
book = books.ensure_one()

35. Domains and Search Filters in Odoo

Domains appear in search(), fields, actions, and record rules.

Domain example

[('state', '=', 'draft'), ('partner_id', '!=', False)]

36. Environment and Context in Odoo

Pass context with with_context(); switch company/user carefully with with_company/with_user.

env tip

self.env.user
self.env.company
self.with_context(lang='en_US').name

37. Access Rights in Odoo

Without ACL rows, users (except admin patterns) cannot access the model.

ACL idea

ir.model.access.csv
group → model → read/write/create/unlink
Install security before views that need it

38. Security Groups in Odoo

Nest implied_ids so Manager inherits User rights.

Group tip

<record id="group_library_user" model="res.groups">
  <field name="name">Library User</field>
</record>

39. Access Control Lists (ACL) in Odoo

One line per group/model combination with boolean CRUD flags.

ACL CSV sketch

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_library_book_user,library.book.user,model_library_book,group_library_user,1,1,1,0

40. Record Rules in Odoo

Use for multi-company and “own documents only” patterns.

Record rule tip

Domain on records
global vs group rules
multi-company company_id domains
Test with non-admin users

41. XML Views in Odoo

Views bind to a model and are selected by priority/mode.

View idea

form / list / kanban / search
calendar / graph / pivot
inherit existing views
bind via actions

42. Form Views in Odoo

Use widgets and invisible/readonly attrs for better UX.

Form sketch

<form>
  <sheet>
    <group>
      <field name="name"/>
      <field name="partner_id"/>
    </group>
  </sheet>
</form>

43. List Views in Odoo

Enable multi-edit and optional fields where useful.

List sketch

<list>
  <field name="name"/>
  <field name="state"/>
</list>

44. Kanban Views in Odoo

Great for CRM stages and visual workflows.

Kanban tip

kanban-box template
group_by stage
quick create
progress bars optional

45. Search Views in Odoo

Search views power saved filters and facets.

Search sketch

<search>
  <field name="name"/>
  <filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
  <group expand="0" string="Group By">
    <filter string="Status" name="groupby_state" context="{'group_by': 'state'}"/>
  </group>
</search>

46. Calendar Views in Odoo

Map start/stop colors and attendees as needed.

Calendar tip

date_start / date_stop
color field
mode month/week/day

47. Graph Views in Odoo

Combine with search group_by for analytics.

Graph tip

<graph type="bar">
  <field name="partner_id" type="row"/>
  <field name="amount" type="measure"/>
</graph>

48. Pivot Views in Odoo

Users can rearrange rows/columns interactively.

Pivot tip

row / col / measure fields
Export analysis
Good for sales/accounting aggregates

49. Tree/List View Customization in Odoo

Use decoration-danger/info based on field expressions.

Decoration tip

<list decoration-danger="state == 'cancelled'">
  <field name="name"/>
  <field name="state"/>
</list>

50. XML Inheritance in Odoo

Inheritance keeps upgrades smoother when core views change.

Inherit tip

<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
  <!-- xpath modifications -->
</field>

51. View XPath in Odoo

Be precise — fragile xpaths break on upstream view changes.

XPath example

<xpath expr="//field[@name='partner_id']" position="after">
  <field name="x_custom_note"/>
</xpath>

52. Odoo Menus

Hide menus with groups for role-based navigation.

Menu sketch

<menuitem id="menu_library_root" name="Library" sequence="10"/>
<menuitem id="menu_library_books" name="Books" parent="menu_library_root" action="action_library_book"/>

53. Window Actions in Odoo

Set domain, context, and view_mode for the action.

Action sketch

<record id="action_library_book" model="ir.actions.act_window">
  <field name="name">Books</field>
  <field name="res_model">library.book</field>
  <field name="view_mode">list,form</field>
</record>

54. Server Actions in Odoo

Useful for bulk actions and automated record updates.

Server action tip

ir.actions.server
code / object_write / multi
Bind to Action menu
Use with base.automation

55. Wizards in Odoo

Wizards collect input then apply logic to target records.

Wizard tip

TransientModel
form view in dialog
button type=object
unlink old transient rows via vacuum

56. Transient Models in Odoo

Do not use TransientModel for persistent business documents.

TransientModel

class BookWizard(models.TransientModel):
    _name = 'library.book.wizard'
    name = fields.Char()

57. Buttons and Smart Buttons in Odoo

Smart buttons show counts and open related action windows.

Button tip

<button name="action_confirm" type="object" string="Confirm" class="btn-primary"/>
<button type="object" class="oe_stat_button" icon="fa-book" name="action_view_loans">
  <field name="loan_count" widget="statinfo" string="Loans"/>
</button>

58. Onchange Methods in Odoo

Onchange is UI-oriented; do not rely on it for server-side security.

onchange

@api.onchange('partner_id')
def _onchange_partner_id(self):
    if self.partner_id:
        self.email = self.partner_id.email

59. Computed Methods in Odoo

Always declare dependencies; avoid N+1 queries inside computes.

Compute tip

@api.depends(...)
loop recordsets
prefetch related fields
store when searchable

60. Constraints and Validation in Odoo

Fail early with clear messages users can act on.

constrains

from odoo.exceptions import ValidationError

@api.constrains('pages')
def _check_pages(self):
    for rec in self:
        if rec.pages < 0:
            raise ValidationError('Pages cannot be negative.')

61. Python Decorators in Odoo

Common ones: model, depends, onchange, constrains, returns.

Decorators list

@api.model
@api.depends
@api.onchange
@api.constrains
@api.returns (less common day-to-day)

62. @api.model in Odoo

Typical for helpers called without browsing specific records.

@api.model

@api.model
def default_get(self, fields_list):
    res = super().default_get(fields_list)
    res['state'] = 'draft'
    return res

63. @api.depends in Odoo

Include relational paths like line_ids.price when needed.

@api.depends

@api.depends('line_ids.price', 'line_ids.qty')
def _compute_total(self):
    ...

64. @api.onchange in Odoo

Return warnings/domains dicts for richer UX.

@api.onchange tip

UI only — not a security gate
Can return {'warning': {...}, 'domain': {...}}
Keep logic light

65. @api.constrains in Odoo

Raise ValidationError for user-facing constraint failures.

@api.constrains tip

Fires on create/write of listed fields
Not a substitute for ACL
Clear error messages

66. QWeb Templates in Odoo

Used for website pages, reports, and some client templates.

QWeb tip

<t t-foreach="docs" t-as="doc">
  <p t-esc="doc.name"/>
</t>

67. Odoo Website Development

Depends on website module; respect public vs logged-in access.

Website tip

controllers → routes
QWeb templates
snippets / themes
website.page records

68. Odoo Website Builder

Custom modules can add snippets and theme options for editors.

Builder tip

Drag-drop building blocks
Theme customize
SEO page settings
Translate website content

69. Odoo Portal

Portal ACLs differ from internal users — test with portal accounts.

Portal tip

portal group users
portal templates
share sales/invoices securely
signature / payment flows

70. Odoo Email Templates

Bind templates to models for Send message / Send email actions.

Email template tip

mail.template
model_id binding
subject + body_html
dynamic fields ${object.name}

71. Automated Emails in Odoo

Configure outgoing mail server before testing delivery.

Automation tip

Automated Actions
mail activity / notifications
outgoing mail server
avoid spam: clear opt-out & content

72. Scheduled Actions / Cron Jobs in Odoo

Keep cron methods idempotent and efficient; log failures.

Cron tip

<record id="ir_cron_library_cleanup" model="ir.cron">
  <field name="name">Library Cleanup</field>
  <field name="model_id" ref="model_library_book"/>
  <field name="state">code</field>
  <field name="code">model.action_cron_cleanup()</field>
  <field name="interval_number">1</field>
  <field name="interval_type">days</field>
</record>

73. Reports in Odoo

QWeb PDF is the standard approach for invoices and custom docs.

Reports tip

ir.actions.report
QWeb PDF templates
paper format
print menu binding

74. QWeb PDF Reports in Odoo

Use company header/footer and t-foreach over docs.

PDF report tip

report_type qweb-pdf
template + external layout
wkhtmltopdf / report engine deps
test with sample records

75. Excel Reports in Odoo

Useful for accounting extracts and operational spreadsheets.

Excel tip

xlsx writer libraries / report_xlsx patterns
Stream large exports
Match columns to user needs

76. Odoo REST API

Community often uses JSON-RPC; custom REST controllers are common for external apps.

REST tip

Custom http Controllers
auth=user/public/bearer patterns
validate input
rate-limit & HTTPS

77. XML-RPC API in Odoo

Classic integration method supported across versions.

XML-RPC idea

import xmlrpc.client
uid = common.authenticate(db, user, password, {})
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True]]])

78. JSON-RPC API in Odoo

Same ORM methods as UI/RPC — respect access rights.

JSON-RPC tip

/jsonrpc endpoint
call authenticate / execute
JSON payloads
session or api key strategies

79. External API Integration in Odoo

Store credentials securely; handle timeouts and retries.

Integration tip

requests / httpx in server methods
system parameters for config
queue jobs for slow calls
log request ids

80. Webhooks Integration in Odoo

Verify signatures and make handlers idempotent.

Webhook tip

HTTP controller route
verify signature/secret
ack quickly, process async
idempotency keys

81. JavaScript in Odoo

Modern Odoo frontend centers on OWL and the assets bundle system.

JS tip

assets in manifest
/** @odoo-module **/
patch existing components
use services (rpc, notification)

82. OWL Framework in Odoo

OWL uses QWeb-like templates, hooks, and props similar to modern component frameworks.

OWL idea

Components + templates
state / hooks
props & env
mount in webclient

83. OWL Components in Odoo

Keep components small; fetch data via ORM/rpc services.

Component tip

// OWL component sketch
class Counter extends Component {
  static template = 'my_module.Counter';
  setup() {
    this.state = useState({ value: 0 });
  }
}

84. Odoo Frontend Development

Prefer extension/patch over forking core assets.

Frontend tip

Field widgets
View compilers
Systray items
SCSS assets
OWL services

85. Odoo Backend Customization

Follow upgrade-safe patterns: inherit, don’t edit core modules.

Backend tip

_inherit models
xpath views
automations & server actions
security for new fields/models

86. Custom Dashboard Development in Odoo

Start with KPI search views; move to OWL when UX needs are richer.

Dashboard tip

board module layouts
graph/pivot actions
client action + OWL
role-based menu visibility

87. Odoo Accounting Module

Enterprise vs Community accounting features differ — check your edition.

Accounting areas

CoA & taxes
Customer/vendor bills
Journals & reconciliation
Financial reports

88. Odoo Sales Module

Customizations often add fields on sale.order and order lines.

Sales tip

sale.order / sale.order.line
Confirm → delivery/invoice
Pricelists
Sales teams

89. Odoo Purchase Module

Integrate with inventory receipts and accounting.

Purchase tip

purchase.order
Vendor pricelists
Incoming shipments
3-way matching concepts

90. Odoo Inventory Module

Inventory is central — test customizations with multi-step routes carefully.

Inventory tip

product.product / template
stock.picking / move
Routes & rules
Valuation basics

91. Odoo CRM Module

Kanban + activities are core CRM UX patterns.

CRM tip

crm.lead
Stages & probabilities
Activities schedule
Lead enrichment optional

92. Odoo Manufacturing Module

Custom modules often extend BoM lines and MO worksheets.

MRP tip

mrp.bom
mrp.production
Work orders
Quality integrations optional

93. Odoo HR Module

HR data is sensitive — tighten record rules and access groups.

HR tip

hr.employee
Time off
Attendance
Payroll (edition-dependent)

94. Odoo Project Management

Link tasks to sales/helpdesk when building service flows.

Project tip

project.project / task
Stages & deadlines
Timesheets
Task dependencies

95. Odoo Website and E-commerce

Syncs with inventory, taxes, and payment providers.

eCommerce tip

Product pages
Cart & checkout
Payment providers
Shipping methods
Customer portal orders

96. Payment Gateway Integration in Odoo

Follow PCI-aware patterns; never log full card data.

Payment tip

payment.provider
Acquirer/provider modules
Callbacks & webhooks
Test mode first

97. Shipping Integration in Odoo

Use delivery methods on sales/transfers; store tracking references.

Shipping tip

delivery carriers
Rate computation
Label printing
Tracking URLs

98. Third-Party API Integration in Odoo

Isolate integration code in dedicated modules.

Connector tip

Auth (OAuth/API key)
Field mapping
Retry / queue jobs
Monitoring & alerts

99. Odoo Data Import

Use external IDs for idempotent re-imports and relational mapping.

Import tip

Enable import option
External ID column
Many2one by name/id
Validate before import

100. Odoo Data Export

For large extracts, prefer server-side reports or scripts.

Export tip

List → Export
Export all / selected fields
IDs + external IDs
Respect access rights

101. Database Migration in Odoo

Always backup DB + filestore; test on a staging copy first.

Migration tip

Backup first
Staging upgrade rehearsal
Module compatibility check
Scripts for data cleanup

102. Odoo Module Upgrade

Bump manifest version; write migration scripts in migrations/ when needed.

Upgrade tip

odoo-bin -c odoo.conf -d mydb -u my_module --stop-after-init

103. Odoo Debugging

Reproduce as a non-admin user to catch ACL/record rule issues.

Debug tip

--log-level=debug
_logger.info(...)
IDE attach to odoo-bin
Check ir.logging / traceback mail

104. Odoo Logging

Avoid logging secrets; structured messages help production support.

Logging

import logging
_logger = logging.getLogger(__name__)
_logger.info('Synced %s partners', len(partners))

105. Odoo Performance Optimization

Watch N+1 mapped loops; use prefetch and read_group for aggregates.

Perf checklist

Avoid N+1 searches in loops
Index domains fields
Batch crons
Workers + limits
Asset bundling in prod

106. Odoo Security Best Practices

Never bypass security with sudo() unless the operation is trusted and audited.

Security checklist

Strong admin_passwd
Least-privilege groups
Record rules for multi-company
Sanitize website controllers
Keep Odoo & Postgres patched

107. Git and Odoo Development Workflow

Ignore filestore, pyc, and local conf secrets.

Git tip

Repo = custom_addons
Branch per feature
PR + module upgrade test
Tag releases matching Odoo version

108. Odoo Module Testing

Tests protect upgrades and refactors of business logic.

Test tip

from odoo.tests.common import TransactionCase

class TestBook(TransactionCase):
    def test_create_book(self):
        book = self.env['library.book'].create({'name': 'Test'})
        self.assertTrue(book.id)

109. Odoo Deployment

Separate staging/production DBs; automate backups of DB + filestore.

Deploy checklist

Nginx/Apache reverse proxy + SSL
systemd service
workers & memory limits
daily backups
monitoring / disk for filestore

110. Odoo Interview Questions

Be ready for ORM, inheritance, security, views, and upgrade topics.

Sample Q&A

Q: _name vs _inherit?
A: _name creates a model; _inherit extends an existing model.

Q: Many2one vs One2many?
A: Many2one stores FK; One2many is inverse list.

Q: Why record rules?
A: Row-level security beyond model ACL.

111. Real-World Odoo Development Project

Include security, views, reports, and a small automation in each project.

Project ideas

Library management
Maintenance requests
Sales commission fields
Inventory label wizard
Website lead form → CRM

112. Final Project – Complete Custom Odoo Module

Ship a production-shaped module (e.g., Library or Service Tickets): models + fields, list/form/search views, menus/actions, security groups/ACL/record rules, wizard, chatter/mail optional, QWeb report or email template, cron or automation, tests, and README with install/upgrade steps.

  1. Define the business model and states.
  2. Implement views, security, and wizard.
  3. Add report/automation and tests.
  4. Document install, upgrade, and demo data.

Final project scope

1. Custom module scaffold + manifest
2. Models with relations & constraints
3. Form/list/search (+ kanban optional)
4. Menus + window actions
5. Security groups + ACL + record rule
6. Wizard (TransientModel)
7. Smart button / status workflow
8. Report or email template
9. Cron or automated action
10. Tests + README + upgrade notes

Suggested structure

my_service_ticket/
  models/
  views/
  security/
  wizard/
  report/
  data/
  tests/

Conclusion

You now have a full Odoo development path: modules, ORM, views, security, website/reports, integrations, and deployment. Finish the final custom Odoo module to turn the lessons into a portfolio-ready addon.

Leave a reply

Your email address will not be published. Required fields are marked *