Introduction to Odoo — From a Python Developer’s Perspective

Series: Odoo 18 Development for Python Developers Target Audience: Python developers who are new to web development and want to learn Odoo Prerequisites: Basic Python knowledge (functions, classes, OOP, pip)


What is Odoo? ERP, Framework, or Both?

If you come from the Python world, you probably know Django (a web framework) and you might know SAP or Oracle (ERP systems). Odoo sits in a unique position — it is both.

Odoo as an ERP (Enterprise Resource Planning)

Out of the box, Odoo gives you a full suite of business applications:

  • Sales — manage quotations, orders, and invoicing
  • Inventory — track products, warehouses, and shipping
  • Accounting — handle invoices, payments, and financial reports
  • HR — manage employees, payroll, and recruitment
  • CRM — track leads and customer relationships
  • Website & eCommerce — build websites and online stores

Think of it like this: if a company needs software to run their business, Odoo can handle almost everything — from sending an invoice to managing a warehouse.

Odoo as a Framework

Here’s where it gets interesting for us as developers. Beneath all those business applications, Odoo is a Python web framework — similar in concept to Django or Flask, but with a very different philosophy.

Odoo provides:

  • An ORM (Object-Relational Mapping) to interact with the database using Python classes
  • A view system that renders UI from XML definitions (no HTML/CSS templates needed for standard views)
  • A module system that lets you install, uninstall, and upgrade features independently
  • A security layer for access control
  • A web client built with JavaScript (using their own framework called OWL)

The key insight: When we “develop in Odoo,” we are not building standalone Python apps. Instead, we are writing modules (think: plugins) that extend or customize the Odoo framework. Our Python code plugs into Odoo’s existing architecture.


Odoo Architecture Overview

Before writing any code, let’s understand how the pieces fit together. If you’ve never worked with web development before, don’t worry — we’ll start from the basics.

Client-Server Architecture

Odoo follows a client-server model. Here’s what that means in simple terms:

┌─────────────────┐         HTTP          ┌──────────────────────┐
│                  │  ◄──────────────────► │                      │
│   Web Browser    │     (JSON-RPC)        │    Odoo Server       │
│   (Client)       │                       │    (Python)          │
│                  │                       │                      │
└─────────────────┘                       └──────────┬───────────┘
                                                      │
                                                      │ SQL
                                                      ▼
                                          ┌──────────────────────┐
                                          │                      │
                                          │    PostgreSQL         │
                                          │    (Database)         │
                                          │                      │
                                          └──────────────────────┘

Let’s break this down:

  • Web Browser (Client): This is what the user sees. Odoo’s entire user interface runs in the browser. It’s a Single Page Application (SPA) built with JavaScript.
  • Odoo Server (Python): This is where YOUR code lives. It handles business logic, processes requests from the browser, and talks to the database. The server is a Python application.
  • PostgreSQL (Database): Odoo exclusively uses PostgreSQL. Not MySQL, not SQLite — only PostgreSQL. All your data (customers, products, invoices, etc.) is stored here.

How a Request Flows

When a user clicks a button in the browser, here’s what happens:

  1. The browser sends a JSON-RPC request to the Odoo server (think of it like an API call)
  2. The Odoo server receives the request and routes it to the appropriate Python method
  3. That Python method uses the ORM to read/write data in PostgreSQL
  4. The server sends a JSON response back to the browser
  5. The browser updates the UI

As an Odoo developer, most of your work happens at step 2 and 3 — writing Python methods that contain business logic and interact with the database through the ORM.

The Three Layers

You can think of Odoo as having three layers:

Layer Technology Your Role
Data Layer PostgreSQL + Odoo ORM Define models (tables) in Python. The ORM creates and manages the actual database tables for you.
Logic Layer Python Write business logic as methods on your models.
Presentation Layer XML (views) + JavaScript (OWL) Define how data is displayed using XML. For advanced UI, write JavaScript components.

Important for Python developers: You almost never write raw SQL. The ORM handles database operations. You also rarely write HTML — the UI is defined in XML, and Odoo renders it for you.


How Odoo Differs from Django/Flask — Mental Model Shift

If you’ve used Django or Flask (even briefly), understanding the differences will help you avoid confusion. If you haven’t used them, skip to the comparison table — it still helps frame how Odoo works.

In Django/Flask, You Build From Scratch

In a typical Django project:

  • You define models (database tables) in models.py
  • You write views (request handlers) in views.py
  • You create HTML templates with Jinja2 or Django Template Language
  • You configure URLs in urls.py
  • You build your app from the ground up

In Odoo, You Extend an Existing System

In Odoo:

  • You define models in Python (similar to Django), but they plug into Odoo’s ORM
  • The UI is defined in XML, not HTML templates
  • You don’t write URL routes — Odoo’s web client handles routing
  • You inherit and extend existing models instead of building from scratch
  • You organize everything into modules that can be installed/uninstalled

Comparison Table

Concept Django/Flask Odoo
Project structure You decide Convention-based module structure
Database ORM Django ORM / SQLAlchemy Odoo ORM (unique to Odoo)
Database Any (SQLite, MySQL, PostgreSQL) PostgreSQL only
UI rendering HTML templates (Jinja2) XML view definitions
URL routing urls.py / @app.route Automatic (actions + menus)
Admin interface Django Admin (optional) Built-in (it IS the interface)
Authentication You configure it Built-in user/group system
Package manager pip Odoo module system
Philosophy “Build what you need” “Extend what exists”

The Biggest Mental Shift

Django/Flask: “I’m building an application.” Odoo: “I’m extending a platform.”

In Odoo, you rarely start from zero. Need a customer management system? Don’t build one — install the Contacts module and extend it. Need invoicing? Install the Accounting module and customize it.

Your job as an Odoo developer is often to:

  1. Install existing modules
  2. Extend their models with new fields
  3. Customize their views with new UI elements
  4. Override their business logic with your own rules

This is a powerful approach, but it requires learning how Odoo’s inheritance system works (we’ll cover this in Lesson 9).


Odoo Editions: Community vs Enterprise

Odoo comes in two editions. As a developer, you need to understand the difference:

Community Edition (CE)

  • License: LGPL v3 (open source, free)
  • Source code: Available on GitHub
  • Includes: Core framework, basic modules (Sales, CRM, Inventory, etc.)
  • Best for: Learning, development, small businesses, custom projects

Enterprise Edition (EE)

  • License: Proprietary (paid subscription)
  • Includes: Everything in CE + advanced modules (Full Accounting, Studio, IoT, etc.)
  • Best for: Production use by medium/large businesses

Which One Should You Use for Learning?

Community Edition. It’s free, open source, and contains everything you need to learn Odoo development. All the core concepts — ORM, views, inheritance, security — are identical in both editions.

The Enterprise Edition mainly adds more business modules and some advanced features. The development patterns are the same.

Throughout this series, we will use Odoo 18 Community Edition.


Key Terminology: Modules, Models, Views, Actions, Menus

Before going further, let’s define the five terms you’ll encounter in every single Odoo lesson:

Module

A module is a self-contained package of functionality. Think of it like a “plugin” or “app.”

  • Each module lives in its own directory
  • It has its own models, views, security rules, and data
  • It can be installed and uninstalled independently
  • It can depend on other modules

Examples of built-in modules: sale (Sales), stock (Inventory), account (Accounting).

Model

A model is a Python class that represents a database table. If you know Django, it’s the same concept as a Django model.

# This is an Odoo model — it creates a table in PostgreSQL
from odoo import models, fields

class Book(models.Model):
    _name = 'library.book'           # This becomes the table name (with dots replaced by underscores)
    _description = 'Library Book'    # Human-readable description

    name = fields.Char(string='Title', required=True)    # A text column
    pages = fields.Integer(string='Number of Pages')      # An integer column
    is_available = fields.Boolean(string='Available?')     # A boolean column

What’s happening here:

  • _name = 'library.book' — This tells Odoo to create a table called library_book in PostgreSQL
  • fields.Char(...) — Creates a VARCHAR column. The string parameter is the label shown in the UI
  • required=True — This field cannot be empty (like NOT NULL in SQL)
  • You don’t write CREATE TABLE — the ORM does it automatically when you install the module

View

A view is an XML definition that describes how a model’s data is displayed in the browser. Odoo supports several view types:

  • Form view — for viewing/editing a single record (like a detail page)
  • List view — for viewing multiple records in a table (like a spreadsheet)
  • Kanban view — for viewing records as cards in columns (like Trello)
  • Search view — for defining filters and search options
<!-- This is a simple list view — it tells Odoo to show name and pages as columns -->
<record id="library_book_list" model="ir.ui.view">
    <field name="name">Book List</field>
    <field name="model">library.book</field>
    <field name="arch" type="xml">
        <list>
            <field name="name"/>           <!-- Shows the "Title" column -->
            <field name="pages"/>          <!-- Shows the "Number of Pages" column -->
            <field name="is_available"/>   <!-- Shows the "Available?" column -->
        </list>
    </field>
</record>

What’s happening here:

  • — This is how you create data in Odoo’s XML files. Here we’re creating a view record
  • model="ir.ui.view" — We’re creating a record in the ir.ui.view table (where all views are stored)
  • library.book — This view is for the library.book model
  • — This defines a list (table) view
  • — Each tag adds a column to the list

Don’t worry about memorizing this syntax now. We’ll go deep into views in Lessons 6 and 7.

Action

An action tells Odoo what to do when something is clicked. The most common type is a window action, which opens a view for a model.

<!-- This action says: "Open the list of books" -->
<record id="library_book_action" model="ir.actions.act_window">
    <field name="name">Books</field>
    <field name="res_model">library.book</field>       <!-- Which model to display -->
    <field name="view_mode">list,form</field>           <!-- Show list view first, form view on click -->
</record>

What’s happening here:

  • model="ir.actions.act_window" — This is a “window action” (the most common action type)
  • res_model — The model this action targets
  • view_mode — A comma-separated list of view types. list,form means: show a list first, and when the user clicks a record, open the form view

A menu item creates an entry in Odoo’s navigation menu. It points to an action.

<!-- This creates a menu entry that triggers the book action -->
<menuitem
    id="library_book_menu"
    name="Books"
    action="library_book_action"
    sequence="10"
/>

What’s happening here:

  • id — A unique identifier for this menu item
  • name — The text shown in the navigation menu
  • action — Which action to trigger when clicked (references the action we defined above)
  • sequence — The order in the menu (lower numbers appear first)

How They Connect

Here’s the full chain:

User clicks Menu → Menu triggers Action → Action opens View → View displays Model data

This is the fundamental flow of Odoo’s UI. Understanding this chain is essential.


The Odoo Module as the Unit of Everything

In Django, your project can be structured however you want. In Odoo, everything is a module, and every module follows a specific structure.

Here’s what a typical Odoo module looks like:

library_app/                    # Module directory (this is your module's root)
├── __init__.py                 # Python package init — imports sub-packages
├── __manifest__.py             # Module metadata — name, version, dependencies
├── models/                     # Your Python model files
│   ├── __init__.py
│   └── book.py                 # Defines the library.book model
├── views/                      # Your XML view files
│   └── book_views.xml          # Form, list, search views for books
├── security/                   # Access control files
│   └── ir.model.access.csv     # Who can read/write/create/delete
├── data/                       # Default data loaded on install
│   └── book_data.xml
├── demo/                       # Demo data (only loaded in demo mode)
│   └── book_demo.xml
└── static/                     # Static assets (icons, JS, CSS)
    └── description/
        └── icon.png            # Module icon shown in the Apps menu

Key points:

  • The directory name (library_app) is your module’s technical name
  • __manifest__.py is the most important file — it tells Odoo everything about your module
  • The models/, views/, security/ structure is a convention, not a requirement — but everyone follows it
  • __init__.py files are required (just like regular Python packages) so Odoo can import your code

We’ll build this structure step by step in Lesson 2.


Setting Up Your First Odoo 18 Development Environment

Let’s get our hands dirty. We’ll set up Odoo 18 on your machine so you can follow along with the rest of the series.

We’ll cover two methods. Choose the one that suits you best:

  • Method A: Docker (recommended — clean, reproducible, no system pollution)
  • Method B: Source Install (more control, closer to production setup)

Docker lets you run Odoo without installing anything on your system except Docker itself.

Step 1: Install Docker

If you don’t have Docker installed, download it from docker.com.

Verify installation:

docker --version
# Expected output: Docker version 24.x or higher

docker compose version
# Expected output: Docker Compose version v2.x or higher

Step 2: Create the Project Structure

# Create a directory for your Odoo project
mkdir odoo18-dev
cd odoo18-dev

# Create a directory for your custom modules
mkdir custom-addons

Step 3: Create the Docker Compose File

Create a file called docker-compose.yml in the odoo18-dev directory:

# docker-compose.yml
# This file defines two services: the Odoo server and the PostgreSQL database

version: '3.8'

services:
  # PostgreSQL database service
  db:
    image: postgres:16                  # Use PostgreSQL 16 (recommended for Odoo 18)
    container_name: odoo18-db
    environment:
      POSTGRES_DB: postgres             # Default database
      POSTGRES_USER: odoo               # Database user (Odoo will connect with this)
      POSTGRES_PASSWORD: odoo_password  # Database password (change in production!)
    ports:
      - "5433:5432"                     # Map to port 5433 to avoid conflicts with local PostgreSQL
    volumes:
      - odoo-db-data:/var/lib/postgresql/data   # Persist database data

  # Odoo server service
  odoo:
    image: odoo:18                      # Official Odoo 18 Docker image
    container_name: odoo18-server
    depends_on:
      - db                              # Wait for database to start first
    ports:
      - "8069:8069"                     # Odoo web interface
      - "8072:8072"                     # Odoo live chat / longpolling
    environment:
      HOST: db                          # Connect to the 'db' service
      USER: odoo                        # PostgreSQL user
      PASSWORD: odoo_password           # PostgreSQL password
    volumes:
      # Mount your custom modules directory into the container
      - ./custom-addons:/mnt/extra-addons

# Named volume to persist database data across container restarts
volumes:
  odoo-db-data:

What each line does:

  • image: postgres:16 — Downloads and runs PostgreSQL 16 in a container
  • image: odoo:18 — Downloads and runs the official Odoo 18 image
  • depends_on: db — Ensures the database starts before Odoo
  • ports: "8069:8069" — Makes Odoo accessible at http://localhost:8069
  • volumes: ./custom-addons:/mnt/extra-addons — Maps your local custom-addons folder into the container, so Odoo can see your modules

Step 4: Start Odoo

# Start both services in the background
docker compose up -d

# Check that both containers are running
docker compose ps

You should see both odoo18-db and odoo18-server in “running” state.

Step 5: Access Odoo

Open your browser and go to: http://localhost:8069

You’ll see the database creation page. Fill in:

  • Master Password: admin (this is the Odoo master password, not the database password)
  • Database Name: odoo18dev
  • Email: admin@example.com
  • Password: admin (this will be your login password)
  • Language: English
  • Country: Choose your country
  • Check “Demo data” — this loads sample data which is useful for learning

Click “Create database” and wait. This may take 1-2 minutes.

Useful Docker Commands

# View Odoo logs (useful for debugging)
docker compose logs -f odoo

# Stop all services
docker compose down

# Stop and remove all data (fresh start)
docker compose down -v

# Restart Odoo after code changes
docker compose restart odoo

Method B: Source Install (Ubuntu/Debian)

This method installs Odoo directly from source code. It gives you more control and is closer to a production setup.

Step 1: Install System Dependencies

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install Python 3.12 and development tools
sudo apt install -y python3.12 python3.12-venv python3.12-dev

# Install PostgreSQL
sudo apt install -y postgresql postgresql-client

# Install other system dependencies required by Odoo
sudo apt install -y \
    git \
    build-essential \
    libxml2-dev \
    libxslt1-dev \
    libldap2-dev \
    libsasl2-dev \
    libjpeg-dev \
    zlib1g-dev \
    libfreetype6-dev \
    liblcms2-dev \
    libopenjp2-7-dev \
    libtiff5-dev \
    node-less \
    npm \
    wkhtmltopdf

What are these packages?

  • python3.12 — Odoo 18 requires Python 3.10+ (3.12 is recommended)
  • postgresql — The database engine
  • git — To clone the Odoo source code
  • The lib*-dev packages — C libraries needed to compile Python packages like Pillow (image processing) and lxml (XML parsing)
  • wkhtmltopdf — Converts HTML to PDF (used for printing reports)
  • node-less and npm — For compiling CSS assets

Step 2: Configure PostgreSQL

# Create a PostgreSQL user for Odoo (same name as your system user)
sudo -u postgres createuser --createdb --no-superuser --no-createrole $USER

# Verify it works
psql -d postgres -c "SELECT version();"

Why --createdb? Odoo needs permission to create new databases (each Odoo instance uses its own database).

Step 3: Clone Odoo Source Code

# Create a workspace directory
mkdir ~/odoo18-workspace
cd ~/odoo18-workspace

# Clone Odoo 18 (community edition) — this may take a few minutes
git clone https://github.com/odoo/odoo.git --branch 18.0 --depth 1

# Create a directory for your custom modules
mkdir custom-addons

What the flags mean:

  • --branch 18.0 — Clone only the 18.0 branch (not the entire history of all branches)
  • --depth 1 — Shallow clone (only the latest commit, saves time and disk space)

Step 4: Set Up Python Virtual Environment

# Create a virtual environment
python3.12 -m venv odoo-venv

# Activate it
source odoo-venv/bin/activate

# Install Odoo's Python dependencies
pip install -r odoo/requirements.txt

# Install Odoo in development mode
pip install -e odoo

Why a virtual environment? It keeps Odoo’s Python packages separate from your system Python. This prevents version conflicts.

Step 5: Create a Configuration File

Create a file called odoo.conf in your workspace:

# ~/odoo18-workspace/odoo.conf

[options]
; Path to your custom modules (add more paths with commas)
addons_path = ./odoo/addons,./custom-addons

; Database settings
db_host = localhost
db_port = 5432
db_user = your_username
db_password = False

; Server settings
http_port = 8069
admin_passwd = admin

; Development settings
dev_mode = reload,xml

; Logging
log_level = info

Important settings explained:

  • addons_path — Where Odoo looks for modules. First path is Odoo’s built-in modules, second is your custom modules
  • db_user — Replace your_username with your actual system username
  • db_password = False — If your PostgreSQL user has no password (local peer authentication)
  • dev_mode = reload,xml — Auto-restarts the server when Python files change, and reloads XML without restart. This is a huge time-saver during development.

Step 6: Start Odoo

# Make sure your virtual environment is activated
source odoo-venv/bin/activate

# Start Odoo with your config file
python odoo/odoo-bin -c odoo.conf

You should see log output ending with something like:

INFO odoo18dev odoo.service.server: HTTP service (werkzeug) running on 0.0.0.0:8069

Now open http://localhost:8069 in your browser and create your database (same steps as Docker Method, Step 5).


Running Odoo, Accessing the Web Client, Developer Mode

The Odoo Web Client

After creating your database and logging in, you’ll see the Odoo home screen with a grid of application icons. This is the Apps page.

Take a moment to explore:

  • Click on Settings (gear icon) — this is where you configure Odoo
  • Click on Apps — this shows all available modules you can install
  • The top menu bar changes depending on which app you’re using

Activating Developer Mode

Developer Mode (also called Debug Mode) is essential for Odoo development. It unlocks:

  • Technical menus (see database structure, view definitions, etc.)
  • Field information on hover
  • Access to edit views directly in the UI
  • Technical settings and menus

How to activate it:

Method 1: Via Settings

  1. Go to Settings (main menu)
  2. Scroll to the bottom of the page
  3. Click “Activate the developer mode”

Method 2: Via URL (Faster)

Add ?debug=1 to your URL:

http://localhost:8069/web?debug=1

For Developer Mode with Assets (also loads unminified JavaScript — useful for JS debugging):

http://localhost:8069/web?debug=assets

What Changes in Developer Mode?

Once activated, you’ll notice:

  1. A debug icon (bug icon) appears in the top menu bar
  2. Technical menus appear under Settings → Technical
  3. Field tooltips — hover over any field in a form to see its technical name, type, and model
  4. Edit View — a small “Edit View” link appears on views, letting you see the XML definition

The Technical menu (Settings → Technical) is incredibly useful. It lets you browse:

  • Models and their fields
  • Views and their XML
  • Actions and menus
  • Security groups and access rules
  • Sequences, email templates, and much more

The Odoo Shell

Odoo provides an interactive Python shell that gives you direct access to the ORM. This is very useful for testing and debugging.

# Docker method:
docker compose exec odoo odoo shell -d odoo18dev

# Source method:
python odoo/odoo-bin shell -c odoo.conf -d odoo18dev

Once in the shell, you can interact with the database:

# Search for all installed modules
modules = env['ir.module.module'].search([('state', '=', 'installed')])
print(len(modules))  # Number of installed modules

# Read a specific partner (customer/contact)
admin = env['res.partner'].browse(1)
print(admin.name)  # Output: "YourCompany"

# Search for partners
partners = env['res.partner'].search([('is_company', '=', True)])
for p in partners:
    print(p.name)

What’s happening here:

  • env — This is the Odoo Environment object. It gives you access to all models
  • env['ir.module.module'] — Access the “Module” model (like from myapp.models import Module)
  • .search([('state', '=', 'installed')]) — Search with a domain filter (we’ll cover domains in detail in Lesson 4)
  • .browse(1) — Get the record with ID = 1

Don’t worry if this looks unfamiliar. We’ll spend three full lessons on the ORM (Lessons 3, 4, and 5).


Summary & What’s Next

Let’s recap what we learned in this lesson:

Key Takeaways

  1. Odoo is both an ERP and a framework. As developers, we write modules that plug into the framework.
  2. Odoo uses a client-server architecture: browser (JavaScript) ↔ server (Python) ↔ database (PostgreSQL).
  3. The mental model shift: In Django/Flask, you build from scratch. In Odoo, you extend what exists.
  4. Community Edition is free and open source — perfect for learning and development.
  5. Five core concepts: Module → Model → View → Action → Menu. They connect like a chain: Menu triggers Action, Action opens View, View displays Model data.
  6. Everything is a module. Your code lives in modules with a specific directory structure.
  7. Developer Mode unlocks technical menus and debugging tools. Always have it on during development.

Quick Reference Card

What Where
Odoo Web Client http://localhost:8069
Developer Mode Settings → Activate developer mode, or ?debug=1
Your Custom Modules ./custom-addons/ (Docker) or ~/odoo18-workspace/custom-addons/ (Source)
Odoo Logs docker compose logs -f odoo (Docker) or terminal output (Source)
Odoo Shell docker compose exec odoo odoo shell -d odoo18dev
Odoo Source Code github.com/odoo/odoo branch 18.0

What’s Next?

In Lesson 2: Anatomy of an Odoo Module, we’ll create our first module from scratch. You’ll learn:

  • The exact purpose of every file in a module
  • How __manifest__.py works
  • How __init__.py chains work in Odoo
  • How to scaffold, install, and upgrade your module

Make sure your Odoo 18 environment is up and running before moving to Lesson 2!


Exercise: Before moving on, try these tasks to make sure your setup is working: 1. Start Odoo and create a database with demo data 2. Log in and activate Developer Mode 3. Go to Settings → Technical → Database Structure → Models and browse the list 4. Open the Odoo Shell and run: env['res.partner'].search_count([]) — this should return the number of contacts in your database 5. Install the “Sales” module from the Apps menu and explore the UI it creates


Next lesson: Lesson 2 — Anatomy of an Odoo Module

Leave a Reply

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