Wprowadzenie
W Odoo domyślnym sposobem łączenia rekordów jest pole Many2one — proste i skuteczne, gdy zawsze wskazujesz jeden konkretny model. Jednak często zachodzi potrzeba, by powiązanie mogło prowadzić do różnych typów dokumentów w zależności od sytuacji: zamówienia sprzedaży, zamówienia zakupu, zlecenia produkcyjnego czy zupełnie innego obiektu. Pole Reference zostało zaprojektowane dokładnie do takich elastycznych powiązań.
Reference to jeden z bardziej uniwersalnych typów pól w ORM Odoo. Pozwala wybrać najpierw typ dokumentu, a potem konkretny rekord z listy dopuszczalnych modeli — zamiast na stałe wskazywać jeden model, tworzy polimorficzne odwołanie dopasowujące się do różnych scenariuszy biznesowych.
W tym materiale wyjaśniam, co dokładnie pole Reference zapisuje, jak zachowuje się w modelu danych Odoo, jak je dodać i dostosować (zarówno przez Odoo Studio, jak i w Pythonie), oraz przedstawiam praktyczne scenariusze, w których rzeczywiście upraszcza model danych i pracę użytkowników.
Czym jest pole Reference w Odoo
W warstwie ORM pole Reference to specjalny typ pola, którego wartość pochodzi z listy modeli podanej w parametrze selection. Dzięki temu różni się od Many2one — nie jest powiązane z jednym, stałym modelem, lecz może wskazywać rekordy z kilku różnych modeli zdefiniowanych w konfiguracji pola.
W bazie danych wartość pola Reference przechowywana jest jako zwykły tekst w formacie model_name,record_id. Na przykład odwołanie do zamówienia sprzedaży numer 42 wygląda jako sale.order,42. To ważne przy bezpośrednich zapytaniach SQL czy tworzeniu filtrów w kodzie.
Dla użytkownika pole Reference działa w dwóch krokach: najpierw wybiera typ dokumentu z listy (np. Zamówienie sprzedaży, Faktura, Zadanie projektowe), potem wybiera konkretny rekord z wybranego modelu za pomocą wyszukiwarki. Po krótkim przyzwyczajeniu obsługa jest intuicyjna i przejrzysta.
Poniżej przykład, jak pole Reference wygląda w definicji Pythona:
from odoo import fields, models
class HelpDeskTicket(models.Model):
_inherit = 'helpdesk.ticket'
related_document = fields.Reference(
selection=[
('sale.order', 'Sale Order'),
('purchase.order', 'Purchase Order'),
('account.move', 'Invoice'),
('project.task', 'Project Task'),
],
string='Related Document',
)
Parametr selection to lista par: nazwa techniczna modelu oraz etykieta widoczna dla użytkownika. To ty wybierasz, które modele będą dostępne — warto dobrać je tak, by odzwierciedlały realne potrzeby procesu biznesowego.
Można też zdefiniować selection dynamicznie — przez metodę, która w czasie wykonania pobiera listę modeli (np. z ir.model). To przydatne w bardzo konfigurowalnych rozwiązaniach, ale należy uważać, bo zbyt długa lista modeli może spowodować dezorientację użytkowników.
W Odoo Studio pole Reference jest dostępne w panelu pól jako „Reference”. Dodając je przez Studio wybierasz, które modele mają być widoczne — bez pisania kodu. To szybki sposób na rozszerzenie formularzy, choć Studio może nie obsługiwać wszystkich zaawansowanych opcji, takich jak dynamiczne metody selection.
Jak pole działa
Zrozumienie, jak Reference zapisuje i przywraca dane, jest kluczowe, jeśli chcesz używać tego pola poprawnie w projektach Odoo.
Przechowywanie w bazie danych
W przeciwieństwie do Many2one, który w bazie trzyma tylko integer (klucz obcy), Reference przechowuje łańcuch tekstowy zawierający zarówno nazwę modelu, jak i ID rekordu, np. sale.order,15. W PostgreSQL zapisuje się to w kolumnie typu VARCHAR. Taki wybór eliminuje referencyjne ograniczenia FK i umożliwia wskazywanie różnych typów rekordów w tym samym polu.
Brak ograniczenia klucza obcego oznacza też, że baza nie wykasuje ani nie zaktualizuje tych odwołań automatycznie, gdy usunięty zostanie wskazywany rekord. Pole nadal będzie zawierać starą wartość tekstową — to istotny aspekt, o którym trzeba pamiętać przy projektowaniu procesów utrzymania danych.
Dostęp do powiązanego rekordu w Pythonie
Gdy odczytasz pole Reference w Pythonie, Odoo zwróci już obiekt rekordowy właściwego modelu — możesz wprost odwoływać się do jego pól, podobnie jak w przypadku Many2one. Jeśli pole jest puste, funkcja zwróci False.
ticket = self.env['helpdesk.ticket'].browse(1)
doc = ticket.related_document
if doc:
print(doc._name) # np. 'sale.order'
print(doc.name) # np. 'S00042'
print(doc.id) # np. 15
To duża zaleta ORM Odoo: mimo że w DB jest zwykły tekst, warstwa aplikacji rozwiązuje go do obiektu rekordu, co ułatwia dalsze operacje w kodzie.
Najważniejsze atrybuty pola
Poniżej lista najistotniejszych parametrów, które możesz skonfigurować dla pola Reference w Odoo:
- selection: lista par definiująca dopuszczalne modele. Może być też nazwą metody (string), która zwróci taką listę dynamicznie.
- string: etykieta pola wyświetlana w interfejsie.
- required: jeśli ustawione, pole jest obowiązkowe — użytkownik musi wybrać typ i rekord przed zapisem.
- readonly: uniemożliwia zmianę wartości z poziomu UI — przydatne, gdy odwołanie ustawia kod lub automatyzacja.
- help: tooltip przy etykiecie pola, tłumaczący użytkownikowi, co powinien wybrać.
- compute: pole Reference może być polem obliczalnym — ustawiasz metodę Pythona, która określi wartość automatycznie zgodnie z logiką biznesową.
Filtrowanie i wyszukiwanie
Ponieważ wartość jest zapisem tekstowym, filtracja wymaga odpowiedniego podejścia: musisz budować domainy operując na sformatowanym stringu.
tickets = self.env['helpdesk.ticket'].search([
('related_document', '=', 'sale.order,15')
])
Możesz też filtrować po typie modelu stosując operator like:
tickets = self.env['helpdesk.ticket'].search([
('related_document', 'like', 'sale.order,')
])
Pamiętaj o tym stringowym sposobie filtrowania przy projektowaniu raportów i pól obliczanych, bo różni się on od typowych filtrów Many2one.
Przykłady zastosowań w biznesie
Gdzie Reference naprawdę pomaga — 5 praktycznych przykładów
1. Zgłoszenia Helpdesku powiązane z dowolnym dokumentem
Zespół wsparcia obsługuje sprawy dotyczące faktur, dostaw, umów czy produktów. Zamiast tworzyć pola osobno dla każdego typu dokumentu, jedno pole Reference na zgłoszeniu pozwala agentowi wybrać odpowiedni typ i konkretny rekord — całe powiązanie mieści się w jednym miejscu.
2. Aktywności CRM powiązane z różnymi dokumentami
Przedstawiciel sprzedaży może zadzwonić w sprawie lejka, oferty, umowy czy zgłoszenia serwisowego. Pole Reference na aktywności pozwala wskazać źródłowy dokument bez więzów do jednego modelu — wygodne przy integracjach CRM i adaptacjach procesu sprzedażowego.
3. Notatki i adnotacje obejmujące różne moduły
Firmy często potrzebują modelu notatek, który można przyczepić do klienta, zadania projektowego, zlecenia produkcyjnego czy zamówienia zakupu. Jedno pole Reference na notatce zapobiega mnożeniu tabel i ułatwia konsolidację zapisu uwag.
4. Uniwersalny workflow zatwierdzania dokumentów
W systemie zatwierdzeń wniosek może dotyczyć zamówienia zakupowego, raportu kosztów, wniosku urlopowego czy umowy. Dzięki Reference ta sama logika zatwierdzania obsłuży wiele typów dokumentów bez tworzenia odrębnych modeli dla każdego z nich.
5. Rachunki kosztów powiązane z projektami lub zamówieniami sprzedaży
W księgowości koszty mogą być przypisane do projektu lub do konkretnego zamówienia sprzedaży. Pole Reference z listą modeli project.project i sale.order daje księgowym elastyczność przypisania wydatku do właściwego źródła, co jest typowe w firmach usługowych i konsultingowych.
Tworzenie i modyfikacja pola Reference
Dodanie pola Reference można zrobić dwiema drogami: szybkie, bezkodowe przez Odoo Studio lub pełne zdefiniowanie w Pythonie dla większej kontroli.
Użycie Odoo Studio
Studio pozwala wstawić pole Reference w formularzu bez pisania kodu — wybierasz je z panelu pól, wskazujesz dozwolone modele i zapisujesz. Pole zostaje utworzone jako pole niestandardowe z prefiksem x_. To dobre rozwiązanie dla szybkich zmian i analityków biznesowych.
Jest to wygodne dla pilnych rozszerzeń, ale pamiętaj, że pola stworzone przez Studio mogą nie obsługiwać w prosty sposób bardziej zaawansowanych opcji, jak dynamiczne selectiony czy compute o skomplikowanej logice.
Implementacja techniczna w Pythonie
Dla deweloperów najlepszą praktyką jest deklarowanie pola Reference bezpośrednio w module Python. Dzięki temu masz pełną kontrolę nad selection, walidacją i logiką obliczającą.
from odoo import api, fields, models
class ApprovalRequest(models.Model):
_name = 'approval.request'
_description = 'Approval Request'
name = fields.Char(string='Request Name', required=True)
@api.model
def _get_document_types(self):
return [
('purchase.order', 'Purchase Order'),
('hr.expense.sheet', 'Expense Report'),
('hr.leave', 'Time Off Request'),
('sale.order', 'Sale Order'),
]
document_ref = fields.Reference(
selection='_get_document_types',
string='Document',
help='Select the document this approval relates to.',
)
Przekazanie nazwy metody jako selection pozwala generować listę warunkowo: filtrować po zainstalowanych modułach, po konfiguracji klienta czy po uprawnieniach — czyli budować wybór inteligentnie i kontekstowo.
Tworzenie pola przez API XML-RPC
Pole Reference możesz też utworzyć zdalnie przez XML-RPC — przydaje się to przy automatycznym provisioningu lub migracjach. Typ pola to 'reference', a selection przesyłasz jako łańcuch, który Odoo zinterpretuje jako listę.
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_related_document',
'field_description': 'Related Document',
'model_id': model_id,
'ttype': 'reference',
'selection': "[('sale.order', 'Sale Order'), ('purchase.order', 'Purchase Order')]",
'state': 'manual',
}]
)
Przy tworzeniu przez API selection przekazywane jest jako string możliwy do ewaluacji przez Pythona — tak Odoo przechowuje te dane w tabeli ir.model.fields.
Dobre praktyki
Zasady i rekomendacje przy pracy z polem Reference
- Utrzymuj listę selection zwięzłą i sensowną. Nie dodawaj wszystkich modeli „bo można” — długi wybór dezorientuje użytkowników i powoduje błędy przy wprowadzaniu danych.
- Używaj Many2one, gdy zawsze wiążesz z jednym modelem. Reference służy do relacji polimorficznych; jeśli model docelowy nigdy się nie zmienia, Many2one jest prostsze i lepiej wspierane przez mechanizmy raportowania.
- Zawsze sprawdzaj wartość null w polach obliczanych. Gdy Reference jest puste, w Pythonie zwróci False — zabezpiecz kod przed odwołaniem się do nieistniejącego obiektu.
- Zadbaj o czyszczenie osieroconych referencji. Ponieważ baza nie wymusza integralności, warto dodać automatyczne działania lub cron, które okresowo wykryją i usuną odwołania do usuniętych rekordów.
- Wybieraj czytelne etykiety w selection. Drugi element pary to tekst widoczny dla użytkownika — używaj nazw przyjaznych biznesowi, np. „Faktura klientów” zamiast technicznego account.move.
- Dokumentuj wybór pola w specyfikacji technicznej. Ponieważ Reference różni się od Many2one, kolejny deweloper powinien od razu wiedzieć, dlaczego wybrano takie rozwiązanie i jakie modele są nim objęte.
Typowe pułapki
Najczęściej popełniane błędy przy pracy z Reference
Traktowanie go jak Many2one w domainach
Często widzimy domeny konstruowane jak dla Many2one, np. [('document_ref','=',15)]. To błędne podejście — przechowywana wartość to tekst sale.order,15, więc filtry muszą porównywać całe sformatowane stringi.
Zapominanie, że usunięte rekordy zostawiają osierocone wartości
Skoro brak FK, usunięcie rekordu nie zresetuje pola Reference — dalej będzie w nim sale.order,42, lecz odczyt zwróci False. Kod powinien obsłużyć taką sytuację, zamiast zakładać, że referencja zawsze wskazuje poprawny rekord.
Nadmierne używanie dynamicznej listy wszystkich modeli
Pobieranie wszystkich modeli z ir.model jako selection brzmi wygodnie, ale praktycznie często prowadzi do setek wpisów w dropdownie — to mylące i sprzyja błędnym wpisom. Ogranicz wybór do sensownych typów dokumentów.
Oczekiwanie natywnego grupowania w raportach
Reference jest tekstem w DB, nie kluczem obcym — standardowe grupowania i pivoty Odoo nie będą działać tak samo jak dla Many2one. Jeśli potrzebujesz grupować po typie powiązanego dokumentu, rozważ obliczane pole, które wydzieli np. nazwę modelu jako osobne pole typu selection lub char.
Mylące rozróżnienie Reference vs Many2one w Studio
W Studio użytkownicy czasem mylą Reference z Many2one, bo oba łączą rekordy. Różnica: Many2one na stałe wskazuje jeden model, Reference pozwala użytkownikowi wybrać model przy każdym wypełnieniu pola. Jeśli potrzebujesz wielomodelowego powiązania, nie obejdzie się bez pola Reference — nie da się łatwo „przerobić” Many2one na Reference.
Podsumowanie
Pole Reference uzupełnia lukę, której Many2one nie pokrywa. Jeśli relacja musi być elastyczna i wskazywać różne typy dokumentów w zależności od kontekstu, Reference jest właściwym wyborem — prostym do zdefiniowania, dostępny w Studio i w pełni integrującym się z kodem Pythona.
Najważniejsze kwestie do zapamiętania to: format przechowywania jako tekst model_name,record_id, brak automatycznego czyszczenia przy usunięciu rekordu oraz konieczność filtrowania po złożonym stringu zamiast po samym ID. Po uwzględnieniu tych różnic pole zachowuje się przewidywalnie i stabilnie.
Niezależnie od tego, czy projektujesz uniwersalny workflow zatwierdzania, łączysz zgłoszenia serwisowe z różnymi dokumentami, czy budujesz system notatek obejmujący wiele modułów — Reference pozwala uniknąć duplikacji logiki i utrzymać porządek w modelu danych.
Potrzebujesz pomocy przy wdrożeniu Odoo?
W Dasolo pomagamy firmom wdrażać i dopasowywać Odoo do realnych procesów. Od projektowania struktury danych, przez implementacje niestandardowych pól, aż po optymalizację istniejących rozwiązań — zapewniamy wiedzę techniczną niezbędną do poprawnej realizacji projektu.
Jeżeli pracujesz nad projektem Odoo i potrzebujesz porady dotyczącej typów pól, architektury danych lub najlepszych praktyk developerskich — skontaktuj się z nami. Chętnie przeanalizujemy Twoją sytuację i zaproponujemy optymalne rozwiązanie.