Wprowadzenie
Gdy zaczynasz przygodę z programowaniem w Odoo, szybko natrafiasz na jedno kluczowe pojęcie: dziedziczenie. W praktyce oznacza ono, że modele mogą rozszerzać się nawzajem i współdzielić pola, dzięki czemu nie trzeba powielać danych ani pisać tej samej logiki w wielu miejscach.
Pola dziedziczone to mechanizm, który pozwala jednemu modelowi odczytywać i udostępniać pola zdefiniowane fizycznie na innym modelu. Zrozumienie tej zasady rozjaśnia wiele zachowań w modelu danych Odoo i ułatwia projektowanie rozszerzeń.
Ten przewodnik objaśnia ideę pól dziedziczonych, opisuje trzy typy dziedziczenia w Odoo, ich wpływ na strukturę bazy danych oraz pokazuje praktyczne scenariusze użycia podczas dostosowywania systemu.
Czym jest pole dziedziczone w Odoo?
W ORM Odoo pole uznaje się za dziedziczone wtedy, gdy model uzyskuje dostęp do pola zdefiniowanego na innym modelu dzięki jednemu z mechanizmów dziedziczenia. Zamiast definiować to pole na nowo, model podrzędny korzysta z istniejącego pola rodzica.
Dzięki temu model danych Odoo pozostaje zwarty i spójny. Na przykład to samo pole name dla kontaktu jest widoczne na zamówieniach sprzedaży, szansach sprzedaży czy fakturach, ponieważ wszystkie te elementy odczytują tę samą wartość ze wspólnego źródła.
Trzy rodzaje dziedziczenia w Odoo
Odoo udostępnia trzy odrębne mechanizmy dziedziczenia modeli — każdy z nich traktuje pola w inny sposób i ma inne konsekwencje dla bazy danych.
1. Dziedziczenie klasyczne
Najpowszechniejsze podejście: deklarujesz _inherit bez nowego _name. W efekcie rozszerzasz istniejący model — dodajesz pola i metody bez tworzenia dodatkowej tabeli. Nowe pola lądują bezpośrednio w tabeli oryginalnego modelu.
To właśnie metoda stosowana przez większość modułów, które rozbudowują standardowe modele. Na przykład moduł CRM dodaje pola do res.partner przez dziedziczenie klasyczne, a wartości trafiają do tej samej tabeli partnerów.
2. Dziedziczenie prototypowe
Kiedy jednocześnie używasz _inherit i _name, tworzysz model bazujący na strukturze rodzica, ale z własną tabelą w bazie. Pola rodzica są skopiowane do nowego modelu — zmiany w potomku nie wpływają na rodzica.
To rozwiązanie jest rzadziej spotykane w prostych dostosowaniach, ale przydaje się, gdy chcesz stworzyć zupełnie nowy model oparty na układzie istniejącego.
3. Dziedziczenie przez delegację
Najbardziej charakterystyczny wariant, realizowany przez _inherits. Model potomny posiada pole Many2one wskazujące na model rodzica i „udostępnia” jego pola tak, jakby były własne. Dane pozostają fizycznie w tabeli rodzica, nie potomka.
W sensie ścisłym to właśnie o takich polach mówią programiści, mówiąc o dziedziczonych polach: nie są one duplikowane, tylko dostępne przez relację przy odczycie i zapisie.
Klasyczny przykład w standardzie Odoo to związek res.users z res.partner. Każdy użytkownik jest też kontaktem — imię, e‑mail czy telefon są przechowywane na rekordzie partnera i dostępne dla użytkownika przez delegację.
Jak działa takie pole
Delegacja — jak to działa w praktyce
Gdy używasz _inherits, ORM tworzy przejście między dwiema tabelami. Przy odczycie pola Odoo podąża po polu Many2one do rekordu rodzica i zwraca wartość zapisaną tam.
Przy zapisie z kolei ORM wpisuje wartość bezpośrednio do rekordu rodzica. Dla developera pole zachowuje się jak natywne, ale w bazie danych jego wartość jest przechowywana w tabeli rodzica.
Ważne następstwo: brak duplikacji danych. Zmiana nazwy partnera od razu widoczna jest we wszystkich miejscach, które odwołują się do tego partnera, w tym na rekordzie użytkownika dziedziczącym po nim.
Dziedziczenie klasyczne i baza danych
W dziedziczeniu klasycznym nowe pola są dodawane do tabeli tego samego modelu — nie powstaje żadna dodatkowa tabela. W bazie danych rozszerzony model i model oryginalny to w praktyce ten sam zbiór rekordów. To najprostszy i najczystszy sposób rozszerzania modeli w codziennych projektach Odoo.
Pola related jako lekkie dziedziczenie
Pole typu related to specjalny wariant pola obliczanego, które odczytuje wartość z powiązanego rekordu przez ścieżkę relacji. Nie jest to dziedziczenie modelu, ale często służy do „wyciągnięcia” danych z innego rekordu bez zmiany struktury modelu.
Przykładowo na zamówieniu sprzedaży możesz mieć pole partner_country_id odwołujące się do partner_id.country_id. Pole zachowuje się jak lokalne na zamówieniu, ale wartość pochodzi z rekordu partnera.
Pola related można zapisać w bazie używając store=True, co przyspiesza wyszukiwanie i filtrowanie, ale zwiększa zużycie miejsca i wymaga rekomputacji przy zmianie źródła.
Jak pola są rozwiązywane w czasie działania systemu
Przy starcie serwera Odoo ładuje definicję modelu i mapuje wszystkie pola, w tym odziedziczone. Zanim model będzie użyty, system już wie, skąd każde pole pochodzi — z własnej tabeli, z tabeli rodzica przez delegację lub ze ścieżki powiązań. Tę mapę Odoo buforuje dla wydajności.
Zastosowania biznesowe
Pola dziedziczone to nie tylko techniczny trik — rozwiązują konkretne potrzeby biznesowe, utrzymując spójność danych w całym systemie bez ich powielania.
1. CRM i sprzedaż: dane kontaktowe
Gdy sprzedawca tworzy lead w CRM, nazwa klienta, telefon i e‑mail pobierane są z rekordu partnera przez pole Many2one. Zmiana danych partnera natychmiast odzwierciedla się we wszystkich powiązanych leadach, ofertach i zamówieniach.
To efekt współdziałania dziedziczenia klasycznego (rozszerzenia partnera o pola CRM) i pól related (wyświetlania danych partnera na zamówieniach).
2. Produkty i warianty
Model produktów w Odoo używa delegacji, aby obsłużyć warianty. product.product (wariant) korzysta z _inherits do product.template. Wspólne pola (nazwa, kategoria, cena, opis) są na szablonie; pola specyficzne dla wariantu (kod kreskowy, referencja) na wariancie.
Dzięki temu możesz mieć kilkadziesiąt wariantów koszulki, które współdzielą nazwę i opis, bez powielania tych wartości w bazie danych.
3. Użytkownicy i kontakty
Każdy użytkownik Odoo jest też kontaktem: res.users używa _inherits = {'res.partner':'partner_id'}, więc dziedziczy pola partnera — imię, mail, telefon, adres i zdjęcie. Aktualizacja e‑maila pracownika zmienia go wszędzie jednocześnie.
4. Magazyn: ruchy i informacje o produkcie
Linie przesunięć magazynowych prezentują opisy produktów pochodzące ze szablonu produktu przez łańcuch powiązań. Kierownicy magazynu widzą aktualne dane produktu bez konieczności ich duplikowania w module magazynowym.
5. Księgowość: pozycje faktur
Pozycje w księdze odwołują się do produktów i kontrahentów. Nazwa produktu, konta i ustawienia podatkowe wyświetlane na fakturze są pobierane z modeli produktu i partnera przez relacje i pola related. Dzięki temu dane księgowe odpowiadają ustawieniom sprzedaży i produktów.
Tworzenie i modyfikacja pól dziedziczonych
Korzystanie z Odoo Studio
Odoo Studio to narzędzie no‑code do modyfikacji modeli i widoków. Pozwala dodać pola bez pisania Pythona — pod spodem Studio stosuje dziedziczenie klasyczne, rozszerzając definicję modelu o nowe pole.
Studio umożliwia też tworzenie pól related. Wybierając "Pole powiązane" wskażesz dowolne pole dostępne przez relację z bieżącego modelu — np. kraj klienta lub NIP z rekordu partnera na zamówieniu sprzedaży.
Dla większości użytkowników biznesowych i konsultantów funkcjonalnych Studio jest wystarczające: zajmie się nazwami pól, migracją bazy i umieszczeniem w widoku automatycznie.
Dostosowania techniczne w Pythonie
Dla deweloperów, którzy tworzą moduły, pola dziedziczone definiuje się w Pythonie przy pomocy klasy models.Model ORM Odoo.
Przykład: dziedziczenie klasyczne, by dodać pole do istniejącego modelu:
class CrmLead(models.Model):
_inherit = 'crm.lead'
x_contract_value = fields.Float(
string='Estimated Contract Value'
)
Przykład: dziedziczenie przez delegację, by utworzyć nowy model współdzielący pola z istniejącego:
class EmployeeProfile(models.Model):
_name = 'hr.employee.profile'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one(
'res.partner',
required=True,
ondelete='cascade'
)
employee_id = fields.Many2one(
'hr.employee',
string='Employee'
)
Przykład: pole related, by pokazać wartość z powiązanego rekordu:
class SaleOrder(models.Model):
_inherit = 'sale.order'
partner_country_id = fields.Many2one(
related='partner_id.country_id',
string='Customer Country',
store=True
)
Poprzez XML-RPC (konfiguracja zdalna)
Pola można też tworzyć programowo przez API XML-RPC, operując na modelu ir.model.fields. To ta sama logika co w Studio i pozwala na tworzenie pól bez bezpośredniego dostępu do serwera.
Aby dodać pole related przez API, tworzy się rekord ir.model.fields z odpowiednim ttype i ustawia parametr related definiując ścieżkę relacji. Takie podejście dobrze sprawdza się przy automatycznych wdrożeniach lub skryptach konfiguracyjnych.
Dobre praktyki
Wybierz odpowiedni typ dziedziczenia do zadania
Używaj dziedziczenia klasycznego, gdy chcesz dodać pola lub metody do istniejącego modelu — to najprostsze rozwiązanie. Delegację stosuj tylko wtedy, gdy potrzebujesz dwóch odrębnych zbiorów rekordów powiązanych ze sobą, np. gdy koncepcja biznesowa rozszerza kontakt, ale nie jest to sam kontakt.
Preferuj pola related do odczytu wartości
Jeśli potrzebujesz jedynie wyświetlić wartość z powiązanego rekordu w formularzu lub liście, pole related jest prostsze niż delegacja. Nie wprowadza nowej zależności strukturalnej i jest łatwiejsze do zrozumienia i utrzymania.
Uważaj z store=True w polach related
Zapisywanie pola related przyspiesza filtrowanie, ale zamienia wartość w kopiowaną kolumnę. Odoo rekomputuje je przy zmianie źródła, co w skrajnych przypadkach może prowadzić do chwilowej niespójności. Stosuj store=True tylko gdy naprawdę potrzebujesz filtrowania lub grupowania na dużych zbiorach danych.
Zawsze prefiksuj własne pola przez x_
Dodając pole do standardowych modeli, rozpoczynaj jego nazwę od x_ (lub stosuj przestrzeń nazw modułu). Zapobiega to konfliktom z polami, które Odoo może dodać w przyszłych wersjach.
Dokumentuj łańcuch dziedziczenia
Przy złożonych rozszerzeniach dodaj krótki komentarz lub notatkę projektową wyjaśniającą skąd pochodzi pole i dlaczego. Pole nazwy x_country_code na zamówieniu może nie wskazywać oczywiście, że źródłem jest partner_id.country_id.code — dokumentacja to rozjaśni.
Poprawnie obsługuj kasowanie kaskadowe
W delegacji rekord rodzica tworzy się automatycznie przy tworzeniu potomka. Przy usuwaniu potomka najczęściej chcesz też usunąć rodzica — ustaw ondelete='cascade' na polu Many2one w _inherits, żeby uniknąć osieroconych rekordów.
Najczęstsze pułapki
Mylące użycie trzech typów dziedziczenia
Częstym błędem początkujących jest użycie _inherit razem z _name, gdy chcieli jedynie rozszerzyć model. To tworzy nowy model zamiast go rozszerzyć. Jeśli nie chcesz nowej tabeli, pomiń _name.
Zapomnienie o stworzeniu rekordu rodzica w _inherits
W delegacji rodzic nie zawsze utworzy się samoczynnie, np. przy tworzeniu rekordu przez API lub skrypt. Trzeba albo pozwolić ORM Odoo utworzyć rodzica przy normalnym create, albo utworzyć rekord rodzica najpierw i przekazać jego ID — pominięcie tego prowadzi do błędów ograniczeń w bazie.
Próba zmiany typu istniejącego pola przez dziedziczenie
Nie można zmienić typu istniejącego pola przez dziedziczenie. Możesz modyfikować etykietę, domain czy help_text, ale nie zamienisz pola typu Char na Integer. Próba spowoduje błąd instalacji modułu.
Nadmierne używanie przechowywanych pól related
Pokusa, by ustawić store=True dla każdego pola related dla wydajności, jest duża, ale prowadzi do wzrostu rozmiaru bazy i kosztów utrzymania. Jeśli pole źródłowe często się zmienia, przechowywane pola będą powodować częste rekomputacje. Stosuj je selektywnie.
Zakładanie, że prawa dostępu potomka obowiązują na pola rodzica
Pola dziedziczone przez delegację są fizycznie na modelu rodzica. Uprawnienia ustawione tylko na modelu potomnym niekoniecznie zabezpieczają te dane na poziomie bazy. Jeśli ograniczysz dostęp do potomka, użytkownicy mogą nadal czytać pola przez rodzica — zawsze sprawdź reguły bezpieczeństwa obu modeli.
Podsumowanie
Pola dziedziczone to fundament architektury Odoo. Relacje użytkownik–partner, wariant–szablon produktu, zamówienie–dane klienta — wszystkie te obszary opierają się na mechanizmach dziedziczenia, które utrzymują spójność danych i eliminują duplikację.
Rozumienie kiedy użyć którego typu dziedziczenia, kiedy lepiej wstawić pole related i jak to wszystko wygląda w bazie pomoże ci stać się bardziej skutecznym twórcą dostosowań Odoo. Dzięki temu napiszesz czytelniejszy kod, zaprojektujesz lepszy model danych i spędzisz mniej czasu na debugowaniu.
Główna myśl jest prosta: ORM Odoo projektuje system tak, by dane miały jedno źródło prawdy i były dostępne z wielu miejsc. To sedno koncepcji pól dziedziczonych i klucz do zachowania spójności modelu danych, gdy system rozrasta się o kolejne moduły.
Potrzebujesz pomocy z wdrożeniem Odoo?
W Dasolo pomagamy firmom we wdrożeniach, rozszerzeniach i optymalizacji Odoo. Niezależnie od tego, czy tworzysz moduł od zera, rozbudowujesz standardowe modele, czy próbujesz zrozumieć nieoczekiwane zachowanie modelu danych — mamy praktyczne doświadczenie, które pozwoli ci działać szybciej i unikać kosztownych błędów.
Jeśli masz pytania dotyczące swojego modelu danych w Odoo, strategii dodawania pól lub implementacji technicznej, chętnie omówimy twoją sytuację i zaproponujemy rozwiązania. Skontaktuj się z nami znajdźmy najlepsze rozwiązanie dla Twojego projektu.