Introduktion
Har du öppnat en försäljningsorder i Odoo och sett raden med orderrader under kundinformationen? Det du ser är ett One2many-fält i praktiken — ett sätt att visa en förälderpost som håller en lista med underposter. För alla som jobbar med Odoo—från slutanvändare till utvecklare—är detta ett av de viktigaste koncepten i datamodellen att förstå.
I den här guiden går vi igenom vad ett One2many-fält innebär i Odoo:s ORM, hur det används i verkliga processer och vilka alternativ du har för att skapa eller konfigurera det — antingen via Odoo Studio eller genom att lägga in fältet i Python-kod.
Oavsett om du jobbar med affärsprocesser och vill förstå hur informationen är strukturerad, eller om du är utvecklare som behöver ett konkret fältexempel, får du här en praktisk genomgång som löser de vanligaste frågorna.
Vad är One2many-fältet i Odoo?
One2many är en relationsfältstyp i Odoo som låter en huvudpost referera till flera underposter i en annan modell.
Kort sagt: en kund kan ha flera fakturor, en försäljningsorder flera orderrader och ett projekt flera uppgifter. Huvudposten visar en samling av relaterade underposter via One2many-fältet.
I användargränssnittet visas One2many ofta som en inbäddad lista i ett formulär. Denna inre tabell ger användaren möjlighet att lägga till, ändra eller ta bort underposter utan att lämna huvudformuläret — vilket gör det till en mycket vanlig och synlig komponent i Odoo.
Hur det skiljer sig från andra relationsfält
Odoo har tre grundläggande relationsfält i ORM:
- Many2one: En post som pekar på en enda post i en annan modell (t.ex. en order som pekar på en kund).
- One2many: En post som är kopplad till flera poster i en annan modell (t.ex. en order kopplad till många orderrader).
- Many2many: Många poster på båda sidor som kan vara länkade till varandra (t.ex. produkter och etiketter).
One2many används när varje underpost hör till exakt en huvudpost. Om en underpost behöver delas av flera huvudposter är Many2many rätt lösning.
En viktig egenskap hos One2many är att det är ett virtuellt fält — det lagrar inte data i sig själv utan visar poster som finns i underpostens modell genom en Many2one-anknytning.
Så fungerar fältet
I databasen finns ingen separat kolumn på huvudtabellen för One2many. Relationerna sparas på undermodellen, där varje rad har en utländsk nyckel (foreign key) som pekar tillbaka mot huvudpostens ID.
Detta är en grundprincip i Odoo: varje One2many har en motsvarande Many2one på den relaterade modellen. One2many fungerar i praktiken som en omvänd sökning — Odoo hämtar alla underposter där Many2one-fältet matchar aktuell huvudpost.
Sambandet mellan One2many och Many2one
När du deklarerar ett One2many-fält i Python anger du två viktiga parametrar:
- comodel_name: den modell som innehåller underposterna.
- inverse_name: namnet på Many2one-fältet på underposten som pekar tillbaka mot huvudposten.
Här är ett enkelt exempel från en modul där ett servicekontrakt är länkat till flera leverabler:
deliverable_ids = fields.One2many(
comodel_name='service.deliverable',
inverse_name='contract_id',
string='Deliverables'
)
I exemplet ovan är contract_id ett Many2one-fält på service.deliverable som pekar tillbaka mot kontraktet. Utan den Many2one-fältet fungerar inte One2many.
Vad som händer i databasen
I Odoo sparas relationen på undermodellens tabell — varje underpost har en kolumn som pekar på parentens ID. Det är där informationen lagras.
När Odoo ska visa en One2many körs en sökning mot undermodellens tabell: hitta alla rader där foreign key matchar huvudpostens ID. ORM:en sköter detta åt dig, så du behöver sällan skriva SQL själv.
Därför räknas One2many till de fält i Odoo som inte skapar nya kolumner i databasen; det är en dynamisk vy över relaterade poster.
Praktiska affärsscenarier
One2many används flitigt i Odoo eftersom det speglar vanliga förälder–barn-relationer. Här är fem vanliga användningsområden från dagligt affärsarbete.
1. Försäljningsorder och orderrader
I försäljningsmodulen finns ofta ett One2many-fält som order_line_ids på sale.order som pekar till sale.order.line. Varje rad innehåller produkt, antal, pris och rabatt — och kan redigeras direkt i ordern.
2. Fakturor och fakturarader
I redovisningen använder account.move One2many för att hantera fakturarader (account.move.line). Fakturaraderna beskriver vad som debiteras, och beloppen summeras av huvudfakturan.
3. Projekt och uppgifter
Projektmodulen visar uppgifter kopplade till ett projekt via ett One2many-fält på project.project. I formuläret kan dessa underposter visas som lista, kanban eller gantt — samma relation driver alla vyer.
4. Kontakter och underkontakter
res.partner har ett child_ids-fält som listar alla kontaktpersoner kopplade till ett företag. Varje underkontakt har i sin tur ett parent_id-fält som pekar tillbaka.
5. Anpassade modeller inom service eller produktion
När du bygger egna moduler är One2many naturligt för scenarion där en post äger en lista med underposter — t.ex. en underhållsorder med flera reservdelar, en kurs med flera kurstillfällen eller ett avtal med flera leverabler.
Denna flexibilitet gör One2many till ett grundläggande verktyg vid anpassning av Odoo för olika branscher.
Skapa eller anpassa fältet
Det finns två huvudsakliga sätt att lägga till ett One2many-fält: via Odoo Studio utan kod, eller genom att definiera fältet i en Python-modul.
Skapa med Odoo Studio
I Studio kan du inte lägga till ett One2many direkt på huvudmodellen utan först skapa Many2one på undermodellen — eftersom One2many alltid bygger på att en inverse finns.
Rekommenderat arbetsflöde i Studio:
- 1) Öppna undermodellen i Studio och skapa ett Many2one-fält som pekar mot huvudmodellen.
- 2) Spara ändringen och växla tillbaka till huvudmodellen i Studio.
- 3) Lägg till ett nytt fält, välj One2many och peka på den relaterade modellen samt inverse-fältet.
- Efter det visas One2many som en inbäddad lista i formuläret.
För många användare är detta det enklaste sättet att skapa relationer utan att skriva kod. Fält som skapas i Studio fungerar i praktiken identiskt med fält definierade i Python.
Skapa med Python i en anpassad modul
Utvecklare som skriver moduler i Python får full kontroll över fältnamn, beteende och filter. Här är ett komplett exempel:
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)
Notera att Many2one-fältet contract_id definieras på undermodellen först, och att inverse_name i One2many-motorn måste matcha det exakta fältnamnet.
Skapa fält via XML-RPC API
När du hanterar Odoo-fält programmässigt kan du skapa One2many via XML-RPC genom modellen ir.model.fields. Principen är densamma: skapa Many2one först och använd sedan relation_field för att peka på det.
Detta är värdefullt om du automatiserar fälthantering över flera miljöer eller behöver masskonfigurera en databas.
Bästa tillvägagångssätt
Utifrån verkliga implementationer finns några tydliga rekommendationer som sparar tid och undviker fel när du arbetar med One2many.
- Skapa alltid Many2one först. One2many kan inte existera utan sin inverse. Oavsett om du använder Studio, Python eller API:et måste Many2one finnas på undermodellen innan du lägger till One2many.
- Använd
_ids-suffixet för namn. Konventionen i Odoo är att One2many-fält slutar på_ids— exempelvisline_idsellertask_ids— vilket tydligt visar att fältet representerar en mängd poster. - Sätt
ondelete='cascade'när det är lämpligt. Om underposter ska tas bort automatiskt när huvudposten raderas, ange detta på Many2one. Det minskar risken för kvarhängande (orphan) poster i databasen. - Håll den inbäddade listan relevant. Visa bara de viktigaste kolumnerna i One2many-listan. För många kolumner gör formuläret tungt och svårnavigerat — använd istället valfria kolumner som kan slås på vid behov.
- Använd domain-filtrering för att begränsa underposter. Med en
domainkan du styra vilka underposter som visas, vilket är praktiskt när flera huvudmodeller delar samma undermodell. - Var försiktig med stora datamängder. Om en huvudpost potentiellt kan få tusentals underposter, undvik att ladda dem alla i formuläret. Överväg att använda en separat listvy eller paginering.
Vanliga fallgropar
Några vanliga misstag dyker upp om och om igen när man jobbar med One2many i Odoo — både vid utveckling och konfiguration.
Att glömma Many2one-inversen
Det vanligaste felet är att skapa ett One2many utan att först ha Many2one på undermodellen. Odoo kommer att ge ett felmeddelande eftersom inverse-fältet saknas. Kontrollera alltid att inverse_name verkligen existerar.
Felaktig skrivsyntax vid uppdatering
När du skriver till ett One2many-fält via Python eller API måste du använda Odoos kommandotuple-syntax — du kan inte tilldela en vanlig Python-lista. Använd Odoo-kommandon för att skapa, uppdatera eller ta bort underposter.
(0, 0, values_dict)för att skapa en ny underpost.(1, child_id, values_dict)för att uppdatera en befintlig underpost.(2, child_id, 0)för att radera en befintlig underpost.(4, child_id, 0)för att lägga till en befintlig underpost i relationen.(5, 0, 0)för att koppla bort alla underposter från huvudposten (utan att ta bort dem).
Att försöka göra något i stil med record.line_ids = [1, 2, 3] fungerar inte i Odoo ORM.
Att förväxla One2many med Many2many
One2many innebär ägarskap: varje underpost tillhör exakt en huvudpost. Om du behöver att samma underpost ska kopplas till flera huvudposter bör du använda Many2many — annars tvingas du duplicera poster och bryter dataintegriteten.
Prestandaproblem med stora underlistor
Om One2many visar hundratals eller tusentals rader i ett formulär påverkas laddningstider negativt. Detta syns ofta i redovisning och lagerhantering. Begränsa antalet rader i listvyn eller använd separata vyer för stora dataset.
Orphan-poster efter borttagning
Om du tar bort en huvudpost utan att ange ondelete='cascade' på Many2one kan underposter bli kvar med ogiltiga eller tomma referenser. Det leder med tiden till röriga data och oväntade fel i vyer och rapporter. Bestäm alltid en tydlig borttagningspolicy.
Sammanfattning
One2many-fältet är en hörnsten i Odoo:s datamodell. Det driver centrala funktioner — från orderrader till fakturarader och projektuppgifter — och när du förstår hur det samspelar med Many2one blir stora delar av Odoo lätta att tolka och bygga vidare på.
Oavsett om du konfigurerar Odoo för din verksamhet, använder Studio eller utvecklar egna moduler, kommer du oftast att använda One2many. Att veta när och hur det ska användas, samt hur du undviker vanliga misstag, sparar tid och minskar risken för datafel.
Vill du fördjupa dig mer finns fler artiklar och tekniska guider i samlingen Odoo Data & API som tar upp avancerade exempel och integrationsmönster.
Behöver du hjälp med din Odoo-implementation?
Dasolo hjälper företag att implementera, anpassa och optimera Odoo så att systemet stödjer just er verksamhet. Vi erbjuder stöd i allt från datamodellsdesign till utveckling av skräddarsydda moduler och praktisk driftoptimering.
Har du frågor kring ditt Odoo-projekt eller vill diskutera hur din datamodell bör designas, kontakta ossså hjälper vi gärna till.