Εισαγωγή
Στις περισσότερες υλοποιήσεις Odoo οι προγραμματιστές χρησιμοποιούν το Many2one για να συνδέσουν εγγραφές. Είναι η απλή, αξιόπιστη λύση όταν η σχέση είναι πάντοτε προς ένα συγκεκριμένο μοντέλο. Όμως υπάρχουν περιπτώσεις όπου η σύνδεση μπορεί να δείχνει σε διαφορετικούς τύπους εγγράφων — παραγγελία πώλησης, παραγγελία αγοράς, αίτημα παραγωγής κ.λπ. Για αυτές τις ανάγκες φτιάχτηκε το Reference field: ένα ευέλικτο εργαλείο που επιτρέπει πολυμορφικούς συνδέσμους.
Το Reference field στο Odoo είναι ένας τύπος πεδίου που επιτρέπει σε μία στήλη να δείχνει σε εγγραφές από διαφορετικά μοντέλα ταυτόχρονα, ανάλογα με την επιλογή του χρήστη. Πρώτα επιλέγεις τον τύπο εγγράφου και μετά την συγκεκριμένη εγγραφή — το αποτέλεσμα είναι μία σύνδεση που προσαρμόζεται σε πολλαπλά σενάρια εργασίας.
Αυτό το άρθρο εξηγεί τι αποθηκεύει το Reference field, πώς συμπεριφέρεται στο μοντέλο δεδομένων, πώς μπορείτε να το προσθέσετε ή να το τροποποιήσετε με Odoo Studio ή Python, και παρουσιάζει πρακτικά παραδείγματα όπου προσθέτει πραγματική αξία στην επιχειρησιακή ροή.
Τι είναι το Reference field στο Odoo
Μηχανικά, το Reference field αποθηκεύει μία αναφορά σε εγγραφή από οποιοδήποτε μοντέλο που έχετε επιλέξει στη λίστα selection. Το διαχωρίζει από το Many2one, που παραμένει πάντα δεσμευμένο σε ένα συγκεκριμένο μοντέλο.
Σε επίπεδο βάσης δεδομένων η τιμή του Reference αποθηκεύεται ως απλή συμβολοσειρά στο format μοντέλο,αναγνωριστικό. Για παράδειγμα, η σύνδεση σε μια παραγγελία πώλησης με id 42 καταχωρείται σαν sale.order,42. Αυτό είναι κρίσιμο να το γνωρίζετε όταν κάνετε άμεσες ερωτήσεις SQL ή φιλτραρίσματα.
Στην διεπαφή χρήστη το Reference εμφανίζεται ως δύο βήματα: πρώτα επιλέγεις τον τύπο εγγράφου από ένα dropdown (π.χ. Παρ. Πώλησης, Τιμολόγιο, Εργασία έργου) και μετά αναζητάς την συγκεκριμένη εγγραφή μέσα στο επιλεγμένο μοντέλο. Μόλις το συνηθίσει η ομάδα, η διαδικασία γίνεται γρήγορη και σαφής.
Παρακάτω θα δείτε ένα παράδειγμα ορισμού Reference field σε Python:
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',
)
Η παράμετρος selection είναι μια λίστα από διπλέτες όπου το πρώτο στοιχείο είναι το τεχνικό όνομα του μοντέλου και το δεύτερο η ετικέτα που βλέπει ο χρήστης στο dropdown. Έχετε πλήρη έλεγχο στο ποια μοντέλα θα εμφανίζονται.
Εναλλακτικά, μπορείτε να δημιουργείτε τη λίστα δυναμικά σε runtime αν αντλείτε δεδομένα από τον πίνακα ir.model. Αυτό δίνει μεγάλη ευελιξία σε εργαλεία που πρέπει να καλύψουν πολλές περιπτώσεις, αλλά χωρίς φιλτράρισμα μπορεί να αποπροσανατολίσει τον τελικό χρήστη.
Στο Odoo Studio το Reference field εμφανίζεται ως τύπος πεδίου με την ένδειξη Reference. Όταν το προσθέτετε μέσω Studio, μπορείτε να επιλέξετε τα διαθέσιμα μοντέλα από το GUI, χωρίς γραφή κώδικα — ιδανικό για γρήγορες προσαρμογές.
Πώς λειτουργεί το πεδίο
Κατανοώντας πώς το Reference αποθηκεύει και ανακτά δεδομένα, μπορείτε να το χρησιμοποιήσετε με ασφάλεια και χωρίς εκπλήξεις στις αναπτύξεις σας.
Αποθήκευση στη βάση δεδομένων
Σε αντίθεση με το Many2one που κρατάει μόνο έναν ακέραιο (τον ξένο κλειδί), το Reference κρατάει μια συμβολοσειρά που περιέχει το όνομα του μοντέλου και το id, π.χ. sale.order,15, αποθηκευμένη σε στήλη τύπου VARCHAR στο PostgreSQL. Αυτή η σχεδιαστική επιλογή επιτρέπει την πολυμορφικότητα, αλλά σημαίνει επίσης ότι δεν υπάρχει ενσωματωμένος περιορισμός ξένου κλειδιού.
Εξαιτίας της απουσίας foreign key, όταν διαγράφετε την αναφερόμενη εγγραφή η τιμή στο Reference δεν καθαρίζεται αυτόματα. Η παλιά συμβολοσειρά παραμένει και πρέπει να το λάβετε υπόψη σε λογική καθαρισμού ή ελέγχων δεδομένων.
Πρόσβαση στην συνδεδεμένη εγγραφή με Python
Όταν διαβάζετε ένα Reference πεδίο στον κώδικα Python, το Odoo επιστρέφει το αντικείμενο εγγραφής του αντίστοιχου μοντέλου — δηλαδή μπορείτε να χρησιμοποιήσετε τα πεδία του όπως θα κάνατε με ένα Many2one. Αν το πεδίο είναι κενό, επιστρέφει False.
ticket = self.env['helpdesk.ticket'].browse(1)
doc = ticket.related_document
if doc:
print(doc._name) # e.g. 'sale.order'
print(doc.name) # e.g. 'S00042'
print(doc.id) # e.g. 15
Αυτό το επίπεδο αφαίρεσης του ORM είναι βολικό: αν και στην DB είναι απλό κείμενο, στο Python αποκτάτε κανονικό record object που μπορείτε να χειριστείτε.
Σημαντικά χαρακτηριστικά πεδίου
Παρακάτω οι πιο χρήσιμες παραμέτροι που μπορείτε να ορίσετε σε ένα Reference field στο Odoo:
- selection: Λίστα διπλετών με τα επιτρεπτά μοντέλα. Μπορεί επίσης να είναι το όνομα μιας μεθόδου (string) που επιστρέφει τη λίστα δυναμικά.
- string: Η ετικέτα που βλέπουν οι χρήστες στο interface.
- required: Κάνει το πεδίο υποχρεωτικό — ο χρήστης πρέπει να επιλέξει τύπο και εγγραφή προτού αποθηκεύσει.
- readonly: Κάνει το πεδίο μόνο για ανάγνωση στην διεπαφή — χρήσιμο όταν το reference θέλετε να ορίζεται από λογική και όχι χειροκίνητα.
- help: Μικρή βοήθεια/tooltip που εμφανίζεται δίπλα στην ετικέτα για να καθοδηγήσει τον χρήστη.
- compute: Όπως σε κάθε Odoo πεδίο, μπορείτε να υπολογίζετε την τιμή προγραμματικά — χρήσιμο για αυτόματες αναφορές ή κανόνες σύνδεσης.
Φιλτράρισμα και αναζητήσεις
Επειδή η τιμή αποθηκεύεται ως συμβολοσειρά, τα domain φιλτραρίσματα χρειάζονται συγκεκριμένη σύνταξη. Για να βρείτε εγγραφές που δείχνουν σε συγκεκριμένο έγγραφο πρέπει να συγκροτήσετε την ίδια τη συμβολοσειρά:
tickets = self.env['helpdesk.ticket'].search([
('related_document', '=', 'sale.order,15')
])
Μπορείτε επίσης να φιλτράρετε κατά τύπο μοντέλου χρησιμοποιώντας τον τελεστή like:
tickets = self.env['helpdesk.ticket'].search([
('related_document', 'like', 'sale.order,')
])
Λάβετε υπόψη αυτή τη συμπεριφορά όταν σχεδιάζετε αναφορές ή υπολογιζόμενα πεδία που βασίζονται σε Reference — δεν φιλτράρονται όπως ένα κανονικό Many2one.
Επιχειρηματικές χρήσεις
Το Reference field λάμπει όταν χρειάζεστε μία ενιαία σύνδεση που μπορεί να δείχνει σε διαφορετικούς τύπους εγγράφων ανά περίπτωση. Ακολουθούν πέντε πρακτικά σενάρια.
1. Helpdesk tickets που συνδέονται με οποιοδήποτε έγγραφο
Η ομάδα υποστήριξης μπορεί να χειρίζεται θέματα που σχετίζονται με τιμολόγια, παραδόσεις, συμβόλαια ή προϊόντα. Αντί να φτιάξετε ξεχωριστό πεδίο για κάθε τύπο, ένα Reference στο ticket επιτρέπει στον τεχνικό να συσχετίσει γρήγορα το κατάλληλο έγγραφο: επιλέγει τον τύπο και μετά την συγκεκριμένη εγγραφή — όλα σε ένα πεδίο.
2. Δραστηριότητες CRM με πολλαπλές πηγές
Σε μια εμπορική ομάδα, εργασίες και follow-ups μπορεί να προέρχονται από lead, προσφορά, υπάρχον συμβόλαιο ή υποστήριξη. Ένα Reference σε custom μοντέλο δραστηριότητας επιτρέπει στο στέλεχος πωλήσεων να συσχετίσει την ενέργεια με την πραγματική πηγή χωρίς περιορισμό σε ένα μόνο μοντέλο.
3. Σημειώσεις και annotations που καλύπτουν πολλά modules
Εταιρίες που κρατούν γενικές σημειώσεις προτιμούν να έχουν ένα ενιαίο μοντέλο σχολίων που να μπορεί να προσκολληθεί σε πελάτη, εργασία έργου, εντολή παραγωγής ή παραγγελία αγοράς. Το Reference αποφεύγει την επανάληψη του μοντέλου της σημείωσης για κάθε τύπο εγγράφου.
4. Ενιαίο workflow έγκρισης
Σε ένα γενικό σύστημα αιτήσεων έγκρισης, το αίτημα πρέπει να δείχνει το έγγραφο που εγκρίνεται — μπορεί να είναι παραγγελία αγοράς, φύλλο δαπανών, άδεια ή συμβόλαιο. Ένα Reference στο μοντέλο approval επιτρέπει στο ίδιο workflow να υπηρετήσει όλους τους τύπους χωρίς πολλαπλά μοντέλα.
5. Δαπάνες συνδεδεμένες με έργα ή παραγγελίες πελάτη
Σε εταιρείες υπηρεσιών, μια δαπάνη μπορεί να αφορά είτε ένα έργο είτε μια παραγγελία πελάτη. Ένα Reference που περιλαμβάνει project.project και sale.order δίνει στους λογιστές την ευελιξία να συσχετίσουν την δαπάνη στο κατάλληλο αντικείμενο.
Δημιουργία ή προσαρμογή του Reference field
Υπάρχουν δύο βασικοί τρόποι για να προσθέσετε ένα Reference: χωρίς κώδικα μέσω Odoo Studio ή με Python για πλήρη έλεγχο.
Χρήση Odoo Studio
Με το Studio προσθέτετε Reference σε φόρμες χωρίς προγραμματισμό: ανοίγετε το Studio, πηγαίνετε στα Fields, επιλέγετε Reference και ορίζετε ποια μοντέλα θα εμφανίζονται. Το Studio αποθηκεύει τέτοια πεδία με πρόθεμα x_, όπως και άλλα πεδία που δημιουργούνται μέσω GUI.
Αυτό είναι ιδανικό για γρήγορες ανάγκες και για επιχειρησιακούς αναλυτές που επεκτείνουν φόρμες χωρίς dev team. Έχετε όμως περιορισμούς σε πιο προχωρημένες ρυθμίσεις όπως δυναμικές μεθόδους selection ή υπολογιζόμενες τιμές.
Τεχνική υλοποίηση σε Python
Για πιο σύνθετες απαιτήσεις, ορίζετε το Reference απευθείας στο Python αρχείο του μοντέλου. Το παρακάτω δείγμα δείχνει πώς να έχετε δυναμική μέθοδο για το selection:
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.',
)
Χρησιμοποιώντας μέθοδο για το selection (περνώντας το όνομά της ως string) κερδίζετε ευελιξία: μπορείτε να φιλτράρετε ανά εγκατεστημένα modules, να εφαρμόσετε επιχειρηματικούς κανόνες ή να χτίσετε τη λίστα από ρυθμίσεις.
Δημιουργία μέσω XML-RPC API
Μπορείτε επίσης να προσθέσετε Reference πεδίο προγραμματικά μέσω της XML-RPC API — χρήσιμο όταν αυτοματοποιείτε παραμετροποιήσεις κατά την ανάπτυξη. Ο τύπος πεδίου είναι reference και η selection περνάει ως string αναπαράσταση της λίστας.
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',
}]
)
Σημειώστε ότι μέσω API η selection στέλνεται σαν string που το Odoo αξιολογεί μετά — αυτός είναι ο τρόπος που αποθηκεύεται στο ir.model.fields.
Καλές πρακτικές
Οδηγίες και κανόνες που αξίζει να ακολουθήσετε όταν δουλεύετε με Reference fields.
- Κρατήστε τη λίστα selection μικρή και ουσιαστική. Μην προσθέτετε κάθε μοντέλο απλώς επειδή μπορείτε. Περιορίστε την σε τύπους εγγράφων που έχουν νόημα για τη χρήση. Μια μεγάλη λίστα μπερδεύει τον χρήστη.
- Χρησιμοποιήστε Many2one όταν πάντα δείχνετε στο ίδιο μοντέλο. Αν ο προορισμός δεν αλλάζει ποτέ, το Many2one είναι απλούστερο, γρηγορότερο στα ερωτήματα και καλύτερο για αναφορές.
- Έλεγχος για null σε υπολογιζόμενα πεδία. Όταν το Reference είναι κενό επιστρέφει
False. Οποιος κώδικας το χρησιμοποιεί πρέπει πρώτα να το ελέγχει για να αποφύγει σφάλματα. - Διαχείριση ορφανών αναφορών. Δεδομένου ότι η DB δεν καθαρίζει αυτόματα τις αναφορές, καλό είναι να έχετε αυτόματες διεργασίες ή scheduled actions που βρίσκουν και καθαρίζουν παλιο-αναφορές σε διαγραμμένες εγγραφές.
- Χρησιμοποιήστε σαφείς, φιλικές ετικέτες στα selection tuples. Η δεύτερη τιμή κάθε tuple είναι αυτό που βλέπει ο χρήστης — προτιμήστε ‘Τιμολόγιο Πελάτη’ αντί για τεχνικά ονόματα όπως ‘account.move’.
- Τεκμηριώστε το πεδίο στις τεχνικές προδιαγραφές. Επειδή συμπεριφέρεται διαφορετικά από το Many2one, ένας μελλοντικός προγραμματιστής ωφελείται αν εξηγήσετε γιατί επιλέξατε Reference και ποια μοντέλα συνδέονται.
Συνηθισμένα λάθη
Τα συχνότερα λάθη που βλέπουμε όταν ομάδες ξεκινούν να χρησιμοποιούν Reference fields.
Σκέψη ότι λειτουργεί όπως το Many2one στα domains
Ένα κοινό λάθος είναι να γράφονται domain όροι σαν να ήταν Many2one, π.χ. [('document_ref', '=', 15)]. Αυτό δεν δουλεύει γιατί η αποθηκευμένη μορφή είναι sale.order,15, όχι ένας ακέραιος. Πρέπει να φτιάξετε την πλήρη συμβολοσειρά στο domain.
Παραβλέποντας ότι οι διαγραμμένες εγγραφές αφήνουν ορφανά
Επειδή δεν υπάρχει constraint, η διαγραφή ενός αναφερόμενου εγγράφου δεν κάνει την τιμή του Reference NULL. Αν το ticket κρατάει sale.order,42 αλλά η παραγγελία διαγράφηκε, η ανάγνωση επιστρέφει False. Κώδικας που περιμένει έγκυρη αναφορά πρέπει να διαχειρίζεται αυτό το σενάριο.
Κακή χρήση της δυναμικής επιλογής «όλα τα μοντέλα»
Η δυνατότητα να επιστρέψετε όλα τα εγκατεστημένα μοντέλα από ir.model είναι ισχυρή αλλά συχνά υπερβολική για το χρήστη. Ένα dropdown με εκατοντάδες επιλογές μπερδεύει και οδηγεί σε λανθασμένη καταχώριση. Περιορίστε τη λίστα σε ουσιώδεις τύπους εγγράφων.
Περιμένοντας native group-by στις αναφορές
Επειδή οι τιμές είναι απλές συμβολοσειρές και όχι foreign keys, δεν μπορείτε να χρησιμοποιήσετε απευθείας τα standard group-by ή pivot του Odoo όπως με Many2one. Αν χρειάζεστε ομαδοποίηση ανά συνδεδεμένο έγγραφο, φτιάξτε computed πεδίο που εξάγει το όνομα μοντέλου ή εφαρμόστε custom κώδικα.
Σύγχυση μεταξύ Reference και Many2one στο Odoo Studio
Μερικοί χρήστες μπερδεύουν τα δύο γιατί και τα δύο συνδέουν με άλλες εγγραφές. Ο διαχωρισμός είναι ότι το Many2one κλειδώνει σε ένα μοντέλο κατά τη δημιουργία, ενώ το Reference αφήνει τον χρήστη να διαλέγει μοντέλο κάθε φορά. Αν φτιάξατε Many2one ενώ χρειαζόταν Reference, συνήθως πρέπει να αναδημιουργήσετε το πεδίο.
Συμπέρασμα
Το Reference field συμπληρώνει το κενό που δεν καλύπτει το Many2one: όταν η σύνδεση πρέπει να είναι ευέλικτη και να δείχνει σε διαφορετικούς τύπους εγγράφων, το Reference είναι το σωστό εργαλείο. Είναι απλό στη δήλωση, συμβατό με Studio για no-code λύσεις και ενσωματώνεται φυσικά σε Python μοντέλα για πιο τεχνικές υλοποιήσεις.
Τα βασικά σημεία που πρέπει να έχετε πάντα υπόψη είναι η αποθήκευση σε μορφή συμβολοσειράς, η απουσία αυτόματου καθαρισμού από τη βάση και το ότι τα φίλτρα πρέπει να συγκροτούν την πλήρη τιμή model,id. Μόλις το κατανοήσετε, το πεδίο λειτουργεί προβλέψιμα μέσα στο Odoo.
Είτε φτιάχνετε ένα γενικό approval workflow, είτε συνδέετε tickets υποστήριξης με πολλούς τύπους εγγράφων, είτε σχεδιάζετε ένα ευέλικτο σύστημα σημειώσεων, το Reference field σας επιτρέπει να κρατήσετε τον κώδικα και το μοντέλο καθαρά χωρίς να διπλοτυπείτε λογική ανά μοντέλο.
Χρειάζεστε βοήθεια με την υλοποίηση του Odoo;
Στην Dasolo υποστηρίζουμε επιχειρήσεις να υλοποιούν, να προσαρμόζουν και να βελτιστοποιούν το Odoo ώστε να ταιριάζει στις πραγματικές τους ροές εργασίας. Από custom λογική πεδίων μέχρι σχεδιασμό δεδομένων και επέκταση λειτουργικότητας, έχουμε την τεχνική εμπειρία για σωστή υλοποίηση.
Αν δουλεύετε πάνω σε έργο Odoo και χρειάζεστε συμβουλευτική για τύπους πεδίων, αρχιτεκτονική δεδομένων ή βέλτιστες πρακτικές ανάπτυξης, επικοινωνήστε μαζί μας. Θα συζητήσουμε την περίπτωσή σας και θα προτείνουμε την κατάλληλη λύση.