Introduktion
Har du nogensinde åbnet en Salgsordre i Odoo og scrollet ned til linjerne under kundens oplysninger? Så har du set One2many‑feltet arbejde: det er den måde, Odoo præsenterer lister af tilknyttede elementer direkte inde i et dokument, og det er afgørende for både brugere og udviklere at forstå, hvordan denne relation fungerer.
Denne vejledning tager dig igennem, hvad One2many er, hvordan Odoo håndterer relationen internt, hvornår du skal vælge den i dit datadesign, og hvordan du opretter eller konfigurerer den — både med Odoo Studio og i kode.
Uanset om du er en forretningsbruger, der vil forstå hvordan data er struktureret, eller en udvikler, der søger en praktisk gennemgang af felttypen, får du her de vigtigste pointer samlet ét sted.
Hvad er One2many‑feltet i Odoo
One2many er en relationsfelt‑type i Odoo, der binder én forældrepost til en samling af børneposter i en anden model — kort sagt: én overordnet enhed med flere underordnede enheder.
Forestil dig en virksomhed: ét kundeopslag kan have mange fakturaer, én salgsordre kan indeholde flere ordrelinjer, og ét projekt kan bestå af en række opgaver. Forældreposten viser en samlet liste over alle disse tilknyttede underposter via One2many‑relationen.
I brugerfladen dukker One2many ofte op som en indlejret tabel direkte i et formularvindue. Den gør det muligt at oprette, rette eller fjerne underelementer uden at forlade forældredokumentet — hvilket er en af de mest synlige og brugte mønstre i Odoo‑grænsefladen.
Hvad der adskiller den fra andre relationsfelter
Odoo har tre primære relationsfelter i sin ORM, som hver især løser forskellige behov i datamodellen.
- Many2one: En post peger på en enkelt post i en anden model (fx en salgsordre, der peger på én kunde).
- One2many: Én post er forbundet til mange poster i en anden model (fx en salgsordre med mange ordrelinjer).
- Many2many: Flere poster på begge sider kan være forbundet til hinanden (fx produkter og tags, hvor hvert tag kan have mange produkter og omvendt).
One2many bruges typisk, når en underpost kun hører til én forælder. Hvis den samme underpost skal deles mellem flere forældre, er Many2many det rigtige valg.
En vigtig teknisk forskel er, at One2many ikke lagrer en kolonne i forælderens tabel. Feltet er virtuelt: det henter relaterede poster fra børnemodellen via en Many2one‑reference på barnet.
Hvordan feltet fungerer
I databasen findes intet nyt felt i forælderens tabel for en One2many. I stedet lever relationen i børnemodellens tabel, hvor hver række har en fremmednøgle, der peger på forælderens id.
Grundprincippet i Odoo‑ORM’en er, at hver One2many har en tilsvarende Many2one på den relaterede model. One2many er i praksis et omvendt opslag: Odoo finder alle barnrækker, hvor Many2one‑feltet matcher forælderens id.
Sammenhængen mellem One2many og Many2one
Når du definerer et One2many‑felt i Python, angiver du to centrale parametre, som styrer relationen.
- comodel_name: navnet på den model, der indeholder børneposterne.
- inverse_name: navnet på Many2one‑feltet på børnemodellen, som peger tilbage på forælderen.
Et typisk eksempel fra et kundetilpasset modul viser, hvordan en servicekontrakt kan være forbundet til flere leverancer via One2many.
deliverable_ids = fields.One2many(
comodel_name='service.deliverable',
inverse_name='contract_id',
string='Deliverables'
)
Her er contract_id et Many2one‑felt defineret på service.deliverable. Uden den eksisterende Many2one kan One2many‑feltet ikke fungere.
Hvad der sker i databasen
I databasen gemmes One2many‑relationen ikke i forælderens tabel; relationen ligger i barnets tabel, hvor hver rad indeholder en fremmednøgle, der peger på forælderen.
Når Odoo indlæser en forælderpost og skal vise One2many‑listen, udfører ORM’en en forespørgsel: find alle rækker i børnetabellen, hvor fremmednøglen svarer til forælderens id. Det er standard relationel adfærd, som håndteres automatisk af Odoo.
Derfor betragtes One2many som et felt, der ikke opretter en ekstra kolonne i databasen, men som giver et dynamisk overblik over relaterede poster.
Praktiske forretningsscenarier
One2many‑felter findes overalt i Odoo, fordi de naturligt modellerer forældre‑/barnrelationer. Her er fem konkrete eksempler fra daglige forretningsprocesser.
1. Salgsordrer og ordrelinjer
I Salg‑modulet kobler order_line_ids på sale.order til sale.order.line. Hver linje indeholder produkt, antal, pris og rabat, og brugeren kan redigere linjerne direkte i salgsordren uden at åbne separate skærmbilleder.
2. Fakturaer og fakturalinjer
Regnskab bruger en One2many på account.move til at holde styr på account.move.line. Hver linje repræsenterer en post på fakturaen, og forældrefakturaen opsummerer beløb fra alle dens linjer.
3. Projekter og opgaver
I Projekt‑appen viser et One2many‑felt på project.project alle tilknyttede opgaver. I formularen kan det vises som en liste, kanban eller Gantt — samme data, forskellige visninger via One2many‑relationen.
4. Kontakter og underkontakter
res.partner har et child_ids One2many, som viser individuelle kontaktpersoner tilknyttet en virksomhed. Hver underkontakt har et parent_id Many2one, der peger tilbage på firmaet.
5. Specialtilpassede modeller i service eller produktion
Når du bygger et custom modul, er One2many naturligt til scenarier, hvor én enhed ejer en samling underposter: fx en vedligeholdelsesordre med brugte reservedele, et kursus med flere kursusdatoer eller en kontrakt med en liste over leverancer.
Denne fleksibilitet forklarer, hvorfor One2many er central i Odoo‑tilpasninger og i at skabe branchetilpassede datamodeller.
Oprettelse og tilpasning af feltet
Der er to typiske måder at oprette One2many på: en no‑code fremgang i Odoo Studio, eller via Python i et tilpasset modul for fuld kontrol.
Brug af Odoo Studio
I Studio kan du ikke oprette One2many direkte på forældremodellen uden først at have Many2one‑feltet på børnemodellen — fordi One2many altid spejler en eksisterende Many2one.
Den anbefalede arbejdsgang i Studio er derfor trinvis:
- Åben børnemodellen i Studio og opret et Many2one‑felt, som peger på forældremodellen.
- Gem ændringen, og gå tilbage til forældremodellen i Studio.
- Tilføj et nyt felt, vælg One2many og vælg den relaterede model samt inverse Many2one‑feltet, når Studio spørger.
- Herefter viser One2many‑feltet sig som en indlejret liste i formularen.
For mange brugere er dette den letteste måde at lave relationer uden kode — Studio‑felter opfører sig som deres Python‑modstykker.
Brug af Python i et custom modul
Udviklere foretrækker ofte at definere One2many i Python for fuld kontrol over navngivning, adfærd og eventuelle domæner. Eksemplet nedenfor illustrerer en komplet implementation.
from odoo import fields, models
class ServiceContract(models.Model):
_name = 'service.contract'
_description = 'Service Contract'
name = fields.Char(string='Contract Name', required=True)
deliverable_ids = fields.One2many(
comodel_name='service.deliverable',
inverse_name='contract_id',
string='Deliverables'
)
class ServiceDeliverable(models.Model):
_name = 'service.deliverable'
_description = 'Service Deliverable'
contract_id = fields.Many2one(
comodel_name='service.contract',
string='Contract',
ondelete='cascade'
)
name = fields.Char(string='Description', required=True)
Bemærk, at Many2one‑feltet (contract_id) først defineres på børnemodellen. inverse_name i One2many‑definitionen skal stemme nøjagtigt overens med dette Many2one‑navn.
Oprettelse via XML‑RPC API
Hvis du administrerer modeller programmatisk, kan du oprette One2many‑felter gennem XML‑RPC ved at arbejde med ir.model.fields. Reglen er den samme: opret Many2one først, og peg derefter One2many mod den ved hjælp af relation_field‑parameteren.
Denne metode er praktisk, når du automatisk skal synkronisere feltopsætning på tværs af miljøer eller bygge automatiserede tilpasningsflows.
Gode fremgangsmåder
Ud fra erfaring med Odoo‑implementeringer er der nogle praksisser, der gentagne gange gør projekter mere stabile og vedligeholdelsesvenlige.
- Allerede fra starten: opret altid Many2one‑feltet på børnemodellen. One2many kan ikke eksistere uden sin inverse, uanset om du bruger Studio, Python eller API.
- Følg navnekonventionen med
_idstil One2many‑felter (fxline_ids,task_ids). Det gør koden mere læsbar og viser tydeligt, at feltet repræsenterer en samling af poster. - Brug
ondelete='cascade'på Many2one, når børnetabellerne skal slettes sammen med forælderen. Det undgår efterladte, ubrugte rækker i databasen. - Hold den indlejrede liste enkel: vis kun de mest relevante kolonner i One2many‑listen. For mange kolonner gør formularen tung og svær at overskue; overvej at gøre sekundære felter valgfrie (optional) for brugeren.
- Brug domæner for at begrænse hvilke underposter, der vises. Det er særligt nyttigt, hvis børnemodellen deles af flere forskellige forældretyper.
- Vær varsom med store datamængder. Hvis én forælder kan have tusindvis af børn, er det ofte nødvendigt at undgå at indlæse alt i formularen — brug separate listevisninger eller paginering for at bevare ydeevnen.
Almindelige faldgruber
De hyppigste fejl, du vil møde i praksis, skyldes som regel manglende forståelse af inverse‑relationen eller forkert skrivemåde mod One2many‑felter.
Glemmer inverse Many2one
Den mest almindelige fejl er at forsøge at oprette en One2many uden først at lave Many2one på børnemodellen. Odoo vil fejle — sørg altid for, at inverse_name rent faktisk findes på barnet.
Forkert skriveform ved opdatering
Når du skriver til One2many gennem Python eller API, skal du bruge Odoos kommando‑tuple‑syntax — du kan ikke sætte en almindelig Python‑liste direkte på feltet.
(0, 0, values_dict)opretter en ny børnepost.(1, child_id, values_dict)opdaterer en eksisterende børnepost.(2, child_id, 0)sletter en eksisterende børnepost.(4, child_id, 0)tilføjer en eksisterende post til relationen.(5, 0, 0)fjerner alle relationer fra forælderen uden at slette børneposterne.
Forsøg på at sætte fx record.line_ids = [1, 2, 3] virker ikke i Odoo‑ORM’en og fører ofte til forvirring.
Forveksling med Many2many
Husk: One2many betyder, at hvert barn kun har én ejer. Hvis et barn skal deles mellem flere forældre, skal du bruge Many2many — ellers ender du med duplikerede rækker og tabt dataintegritet.
Ydeevneproblemer med store lister
Hvis One2many viser hundreder eller tusinder af linjer i en formular, bliver siden langsom. Det ses ofte i økonomi (fakturalinjer) og lagerstyring. Overvej at bruge limit i visningen eller flytte visningen til et separat listebillede for store datasæt.
Orfane‑rækker efter sletning
Sletter du en forælder uden at have ondelete='cascade' på Many2one, kan der blive efterladt børnerækker med nul eller ugyldig reference. Det skaber rod i databasen og uventet adfærd i rapporter og visninger — fastlæg altid en slettepolitik i designfasen.
Afslutning
One2many er en af grundpillerne i Odoo‑ORM’en. Den ligger bag mange centrale funktioner — fra ordrelinjer til fakturalinjer og projektopgaver. Når du først forstår dens afhængighed af Many2one, bliver Odoo's datamodel langt mere overskuelig og lettere at udvide.
Uanset om du konfigurerer Odoo for din virksomhed, bruger Studio eller bygger et modul fra bunden, vil One2many være et værktøj, du ofte får brug for. Kendskab til korrekt oprettelse, navngivning og faldgruber sparer tid og forebygger dataproblemer.
Vil du dykke videre i Odoo‑felter og API‑emner, så kig forbi resten af samlingen ’Odoo Data & API’ for flere dybdegående artikler og tekniske guides.
Brug for hjælp til din Odoo‑implementering?
Dasolo hjælper virksomheder med at implementere, tilpasse og optimere Odoo, så systemet passer til deres forretningsprocesser. Vi assisterer med alt fra datamodeldesign og specialmoduler til feltoprettelse og optimering af eksisterende installationer.
Hvis du har spørgsmål til dit Odoo‑projekt eller ønsker sparring om, hvordan du bedst strukturerer dine data, kontakt osogså gerne — vi står klar til at hjælpe.