So erstellen Sie benutzerdefinierte Odoo-Module: Ein Entwicklerhandbuch zu OWL, ORM und Vererbung
Wenn die 82 offiziellen Module und über 40.000 Community-Module von Odoo Ihre genauen Geschäftsanforderungen nicht abdecken, füllt die Entwicklung benutzerdefinierter Module die Lücke. Dieser Leitfaden behandelt die Grundlagen der Erstellung von Odoo-Modulen im Jahr 2026, einschließlich der Modulstruktur, des OWL-Frontend-Frameworks, ORM-Mustern, Vererbungsmechanismen und Best Practices im Einklang mit den Richtlinien der OCA (Odoo Community Association).
Was ist ein benutzerdefiniertes Odoo-Modul?
Ein benutzerdefiniertes Odoo-Modul ist ein eigenständiges Paket aus Python-Backend-Logik, XML-Ansichtsdefinitionen, JavaScript-Frontend-Komponenten und Sicherheitsregeln, das die Funktionalität von Odoo erweitert. Module können völlig neue Funktionen hinzufügen, bestehendes Verhalten ändern oder Odoo in externe Systeme integrieren. Jedes Teil von Odoo selbst ist ein Modul, wodurch die Architektur von Natur aus erweiterbar ist.
Modulverzeichnisstruktur
Ein gut organisiertes Modul folgt dieser Standardstruktur:
my_custom_module/
├── __init__.py # Python package init
├── __manifest__.py # Module metadata and dependencies
├── models/
│ ├── __init__.py
│ └── my_model.py # Business logic and data models
├── views/
│ ├── my_model_views.xml # Form, tree, and kanban views
│ └── menu.xml # Menu items and actions
├── security/
│ ├── ir.model.access.csv # Access control list
│ └── security.xml # Record rules and groups
├── data/
│ └── data.xml # Default data records
├── static/
│ └── src/
│ ├── js/ # OWL components
│ ├── css/ # Stylesheets
│ └── xml/ # QWeb templates
├── wizard/ # Transient models for wizards
├── reports/ # QWeb report templates
└── tests/ # Unit tests
Die Manifestdatei
Die Datei __manifest__.py definiert die Identität Ihres Moduls:
{
'name': 'My Custom Module',
'version': '18.0.1.0.0',
'category': 'Custom',
'summary': 'Short description of what the module does',
'description': """
Long description with details about
features and configuration.
""",
'author': 'ECOSIRE',
'website': 'https://ecosire.com',
'license': 'LGPL-3',
'depends': ['base', 'sale', 'stock'],
'data': [
'security/ir.model.access.csv',
'views/my_model_views.xml',
'views/menu.xml',
'data/data.xml',
],
'assets': {
'web.assets_backend': [
'my_custom_module/static/src/js/**/*',
'my_custom_module/static/src/css/**/*',
'my_custom_module/static/src/xml/**/*',
],
},
'installable': True,
'application': False,
'auto_install': False,
}
Versionskonvention: {odoo_version}.{major}.{minor}.{patch} (z. B. 18.0.1.0.0).
Arbeiten mit dem ORM
Odoos Object-Relational Mapping (ORM) ist die Grundlage aller Backend-Entwicklung. Modelle werden Datenbanktabellen zugeordnet, und das ORM bietet CRUD-Operationen, berechnete Felder, Einschränkungen und Workflow-Management.
Ein Modell definieren
from odoo import models, fields, api
class ProjectTask(models.Model):
_name = 'my_module.task'
_description = 'Project Task'
_order = 'priority desc, create_date desc'
name = fields.Char(string='Task Name', required=True)
description = fields.Html(string='Description')
state = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In Progress'),
('done', 'Done'),
('cancelled', 'Cancelled'),
], default='draft', tracking=True)
assigned_to = fields.Many2one('res.users', string='Assigned To')
deadline = fields.Date(string='Deadline')
priority = fields.Selection([
('0', 'Normal'),
('1', 'Important'),
('2', 'Urgent'),
], default='0')
tag_ids = fields.Many2many('my_module.tag', string='Tags')
progress = fields.Float(compute='_compute_progress', store=True)
Referenz zu Feldtypen
| Feldtyp | Python-Typ | Anwendungsfall | |---|---|---| | Char | str | Kurztext (Name, Referenz) | | Text | str | Langer Klartext | | HTML | str | Rich-Text-Inhalt | | Ganzzahl | int | Ganze Zahlen | | Float | schweben | Dezimalzahlen | | Boolescher Wert | bool | Wahr/Falsch-Flags | | Datum | Datum | Datum ohne Uhrzeit | | Datum/Uhrzeit | Datum/Uhrzeit | Datum mit Uhrzeit | | Auswahl | str | Dropdown-Auswahl | | Many2one | int | Link zu einem Datensatz | | One2many | Liste | Umkehrung von Many2one | | Viele2viele | Liste | Link zu mehreren Datensätzen | | Binär | Bytes | Dateianhänge |
Berechnete Felder und Einschränkungen
@api.depends('subtask_ids.state')
def _compute_progress(self):
for task in self:
total = len(task.subtask_ids)
done = len(task.subtask_ids.filtered(
lambda t: t.state == 'done'
))
task.progress = (done / total * 100) if total else 0
@api.constrains('deadline')
def _check_deadline(self):
for task in self:
if task.deadline and task.deadline < fields.Date.today():
raise ValidationError(
"Deadline cannot be in the past."
)
Vererbungsmechanismen
Odoo bietet drei Arten der Vererbung, die jeweils einem anderen Zweck dienen:
1. Klassenvererbung (Erweiterung)
Erweitern Sie ein vorhandenes Modell, indem Sie Felder hinzufügen oder Methoden überschreiben. Dies ist das häufigste Muster.
class SaleOrderExtend(models.Model):
_inherit = 'sale.order'
custom_reference = fields.Char(string='Custom Ref')
approved_by = fields.Many2one('res.users')
def action_confirm(self):
# Add custom logic before standard confirmation
for order in self:
if order.amount_total > 10000 and not order.approved_by:
raise UserError("Orders over $10,000 require approval.")
return super().action_confirm()
2. Prototypenvererbung
Erstellen Sie ein neues Modell, das alle Felder und Methoden aus einem vorhandenen Modell kopiert.
class CustomPartner(models.Model):
_name = 'my_module.partner'
_inherit = 'res.partner' # Copies structure
_description = 'Custom Partner'
3. Delegationsvererbung
Erstellen Sie ein neues Modell, das über einen Many2one-Link an ein vorhandenes Modell delegiert. Die Felder des übergeordneten Modells werden im untergeordneten Modell transparent angezeigt.
class LibraryMember(models.Model):
_name = 'library.member'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one('res.partner', required=True,
ondelete='cascade')
membership_date = fields.Date()
member_number = fields.Char()
Das OWL Framework (Frontend)
Odoo 18 verwendet OWL (Odoo Web Library) als Frontend-Framework. OWL ist ein komponentenbasiertes Framework, das React oder Vue ähnelt, aber speziell für die Bedürfnisse von Odoo entwickelt wurde.
Grundlegende OWL-Komponente
/** @odoo-module */
import { Component, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
class TaskDashboard extends Component {
static template = "my_module.TaskDashboard";
setup() {
this.state = useState({
tasks: [],
filter: 'all',
});
this.loadTasks();
}
async loadTasks() {
this.state.tasks = await this.env.services.orm.searchRead(
"my_module.task",
[["state", "!=", "cancelled"]],
["name", "state", "assigned_to", "deadline"]
);
}
get filteredTasks() {
if (this.state.filter === 'all') return this.state.tasks;
return this.state.tasks.filter(
t => t.state === this.state.filter
);
}
}
QWeb-Vorlage (XML)
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.TaskDashboard">
<div class="o_task_dashboard">
<div class="task-filters">
<button t-on-click="() => state.filter = 'all'">All</button>
<button t-on-click="() => state.filter = 'in_progress'">
In Progress
</button>
</div>
<div class="task-list">
<t t-foreach="filteredTasks" t-as="task" t-key="task.id">
<div class="task-card">
<span t-esc="task.name"/>
</div>
</t>
</div>
</div>
</t>
</templates>
Sicherheitskonfiguration
Jedes Modell benötigt explizite Zugriffsregeln. Ohne sie kann kein Benutzer auf die Daten des Modells zugreifen.
Zugriffskontrollliste (ir.model.access.csv)
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_task_user,task.user,model_my_module_task,base.group_user,1,1,1,0
access_task_manager,task.manager,model_my_module_task,my_module.group_manager,1,1,1,1
Regeln aufzeichnen (security.xml)
<record id="task_own_rule" model="ir.rule">
<field name="name">Own Tasks Only</field>
<field name="model_id" ref="model_my_module_task"/>
<field name="domain_force">
[('assigned_to', '=', user.id)]
</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
</record>
Testen Sie Ihr Modul
Odoo unterstützt Python-Unit-Tests mithilfe des unittest-Frameworks mit Odoo-spezifischen Testklassen:
from odoo.tests.common import TransactionCase
class TestTask(TransactionCase):
def setUp(self):
super().setUp()
self.task = self.env['my_module.task'].create({
'name': 'Test Task',
'state': 'draft',
})
def test_task_creation(self):
self.assertEqual(self.task.state, 'draft')
self.assertEqual(self.task.progress, 0)
def test_deadline_constraint(self):
with self.assertRaises(ValidationError):
self.task.write({
'deadline': fields.Date.subtract(
fields.Date.today(), days=1
),
})
Führen Sie Tests aus mit: odoo-bin -d test_db --test-enable -i my_custom_module --stop-after-init
Häufig gestellte Fragen
F: Wie lange dauert die Erstellung eines benutzerdefinierten Odoo-Moduls? Einfache Module (neue Felder, Basisansichten) dauern 1-3 Tage. Mittlere Module (neue Modelle, Workflows, Berichte) dauern 1-3 Wochen. Komplexe Module (Multimodellsysteme, externe Integrationen, kundenspezifische OWL-Komponenten) dauern 4–12 Wochen. Für Unternehmen, die benutzerdefinierte Module benötigen, aber keine internen Odoo-Entwickler haben, stellen Sie einen erfahrenen Odoo-Entwickler ein aus unserem Team.
F: Soll ich den Odoo-Kerncode ändern oder ein separates Modul erstellen? Erstellen Sie immer ein separates Modul. Das Ändern des Kerncodes beeinträchtigt die Aktualisierbarkeit und führt zu Zusammenführungskonflikten bei Versionsaktualisierungen. Verwenden Sie die Vererbung, um vorhandene Modelle und Ansichten aus Ihrem benutzerdefinierten Modul zu erweitern.
F: Was sind OCA-Richtlinien? Die Odoo Community Association (OCA) veröffentlicht Codierungsstandards für die Modulqualität, einschließlich Namenskonventionen, Dokumentationsanforderungen, Erwartungen an die Testabdeckung und Regeln für den Codestil. Durch die Einhaltung der OCA-Richtlinien wird sichergestellt, dass Ihr Modul wartbar und mit dem breiteren Community-Ökosystem kompatibel ist.
Professionelle Hilfe erhalten
Das Erstellen benutzerdefinierter Odoo-Module erfordert Kenntnisse in Python, JavaScript, PostgreSQL und den Framework-Konventionen von Odoo. Egal, ob Sie eine einfache Felderweiterung oder ein komplexes System mit mehreren Modulen benötigen, die [Odoo-Anpassungsdienste] (/services/odoo/customization) von ECOSIRE liefern produktionsbereite Module, die nach OCA-Standards erstellt wurden.
Kontaktieren Sie uns, um Ihre individuellen Modulanforderungen zu besprechen und einen Kostenvoranschlag für die Entwicklung zu erhalten.
Geschrieben von
ECOSIRE Research and Development Team
Entwicklung von Enterprise-Digitalprodukten bei ECOSIRE. Einblicke in Odoo-Integrationen, E-Commerce-Automatisierung und KI-gestützte Geschäftslösungen.
Verwandte Artikel
Amazon.de Odoo-Integration: Verkaufen auf Deutschlands größtem Marktplatz mit Odoo ERP
So integrieren Sie Amazon.de mit Odoo ERP für den deutschen Markt. Deckt Versand durch Amazon, europaweite Abwicklung, deutsche Mehrwertsteuer, VerpackG-Konformität und Abrechnungsabstimmung ab.
Einstieg in den deutschen E-Commerce-Markt mit Odoo: Schritt-für-Schritt-Anleitung für internationale Verkäufer
Vollständiger Leitfaden für internationale Verkäufer, die in den deutschen E-Commerce-Markt einsteigen. Umfasst Marktanalyse, gesetzliche Anforderungen, Mehrwertsteuerregistrierung, Marktplatzauswahl und Odoo ERP-Einrichtung für den Verkauf an deutsche Verbraucher.
Deutsche E-Commerce-Retouren mit Odoo verwalten: Strategien für renditestarke Märkte
So bewältigen Sie die hohen E-Commerce-Retourenquoten in Deutschland mit Odoo ERP. Deckt Workflows zur Retourenabwicklung, Analyse von Ursachencodes, Wiederauffüllungsautomatisierung und marktplatzspezifische Richtlinien für Zalando, Otto, Amazon.de und Kaufland ab.