Εισαγωγή
Το Many2One είναι το βασικό «σώμα σύνδεσης» στο μοντέλο δεδομένων του Odoo. Όταν συνδέεις μια παραγγελία με πελάτη, βάζεις ένα προϊόν σε κατηγορία ή συνδέεις μια εργασία με ένα έργο, χρησιμοποιείς αυτή τη σχέση. Κατανοώντας το Many2One, αποκτάς την ικανότητα να σχεδιάζεις λογικά και βιώσιμα δεδομένα που συμπεριφέρονται καλά σε όλο το σύστημα.
Από την οπτική της επιχείρησης, τα Many2One κάνουν το Odoo ένα ενιαίο περιβάλλον· χωρίς αυτά, κάθε εφαρμογή θα λειτουργούσε ανεξάρτητα. Με τις σχέσεις αυτές, οι εγγραφές «συζητούν» μεταξύ τους και οι χρήστες κινούνται εύκολα από ένα έγγραφο σε ένα άλλο, χωρίς να χρειάζεται να γνωρίζουν τη δομή της βάσης δεδομένων.
Ο οδηγός αυτός εξηγεί τι αποθηκεύει ένα Many2One, πώς συμπεριφέρεται στο ORM και στο περιβάλλον χρήστη, πώς να το προσθέσετε με Studio ή Python, και παρουσιάζει πρακτικά παραδείγματα από CRM, Πωλήσεις, Αποθήκη και Λογιστήριο.
Τι είναι το πεδίο Many2One στο Odoo
Σε επίπεδο ORM, το Many2One δημιουργεί έναν σύνδεσμο από μία εγγραφή προς μία μοναδική εγγραφή σε άλλο μοντέλο. Το όνομα περιγράφει τη σχέση από την πλευρά του τρέχοντος μοντέλου: πολλά αρχεία εδώ μπορούν να δείχνουν σε ένα αρχείο εκεί. Έτσι, πολλές παραγγελίες πωλήσεων μπορούν να σχετίζονται με έναν πελάτη, και πολλά προϊόντα με μία κατηγορία προϊόντων.
Σε επίπεδο βάσης, το Many2One αποθηκεύεται ως ξένο κλειδί στον πίνακα της τρέχουσας οντότητας. Για παράδειγμα, αν μια παραγγελία δείχνει στον πελάτη με ID 42, η στήλη partner_id στον πίνακα sale_order θα περιέχει την τιμή 42. Το Odoo αναλαμβάνει αυτόματα τη σύνδεση και την εμφάνιση του ονόματος της σχετικής εγγραφής.
Στο περιβάλλον χρήστη, το Many2One εμφανίζεται σαν λίστα επιλογής ή πεδίο typeahead. Ο χρήστης πληκτρολογεί μερικούς χαρακτήρες, το σύστημα προτείνει ταιριαστές εγγραφές και η επιλογή του θέτει τον σύνδεσμο. Το εμφανιζόμενο κείμενο είναι το όνομα της συνδεδεμένης εγγραφής — όχι το εσωτερικό ID — γι’ αυτό η εμπειρία χρήστη είναι άμεσα κατανοητή.
Παράδειγμα ορισμού στο Python μοντέλο:
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
x_account_manager_id = fields.Many2one(
comodel_name='res.users',
string='Account Manager',
ondelete='set null',
)
Το comodel_name είναι το τεχνικό όνομα του στόχου. Το ondelete καθορίζει τη συμπεριφορά όταν η συνδεδεμένη εγγραφή διαγράφεται: cascade (διαγραφή και της τρέχουσας εγγραφής), set null (καθαρισμός του πεδίου) ή restrict (απόρριψη της διαγραφής αν υπάρχουν εξαρτήσεις).
Στο Odoo Studio το πεδίο εμφανίζεται στην εργαλειοθήκη ως Many2One. Όταν το σύρεις στη φόρμα, επιλέγεις από ποιο μοντέλο θα δείχνει και το Studio δημιουργεί το πεδίο αυτόματα — ιδανικό για επιχειρήσεις που θέλουν γρήγορες προσαρμογές χωρίς κώδικα.
Πώς λειτουργεί το πεδίο
Όταν διαβάζεις ένα Many2One μέσω του ORM, παίρνεις ένα recordset που περιέχει την συνδεδεμένη εγγραφή. Αν το πεδίο είναι κενό, το recordset είναι κενό. Στο Python μπορείς να προσπελάσεις απευθείας τα πεδία της συνδεδεμένης εγγραφής με dot notation.
order = self.env['sale.order'].browse(1) customer_name = order.partner_id.name customer_city = order.partner_id.city
Αυτή η αλυσιδωτή προσπέλαση είναι ένα από τα πιο πρακτικά χαρακτηριστικά του Odoo: δεν χρειάζεσαι χειροκίνητες JOIN εντολές ή ξεχωριστά ερωτήματα. Το ORM φροντίζει για τις βάσεις και επιστρέφει τα αποτελέσματα σε υψηλού επιπέδου δομές.
Μέσω του XML-RPC API, ένα Many2One επιστρέφεται ως λίστα δύο στοιχείων: το ακέραιο ID της σχετικής εγγραφής και το εμφανιζόμενο όνομα — για παράδειγμα [42, "Acme Corp"]. Εάν το πεδίο είναι κενό, επιστρέφεται False. Αυτό είναι σημαντικό όταν επεξεργάζεστε απαντήσεις API σε scripts.
Βασικά χαρακτηριστικά του πεδίου
Παρακάτω τα πιο σημαντικά attributes που μπορείτε να ρυθμίσετε σε ένα Many2One στο Odoo:
- comodel_name: Το τεχνικό όνομα του στοχευόμενου μοντέλου. Είναι το μοναδικό απαιτούμενο όρισμα.
- ondelete: Τι συμβαίνει όταν η συσχετιζόμενη εγγραφή διαγράφεται. Επιλογές: 'cascade', 'set null', 'restrict'. Προεπιλογή συνήθως 'set null'.
- domain: Φίλτρο που περιορίζει ποιες εγγραφές μπορούν να επιλεγούν στη λίστα. Π.χ. domain=[('customer_rank', '>', 0)] περιορίζει τους επιλογείς σε πελάτες.
- context: Επιπλέον τιμές context που περνούν όταν ανοίγει ο σχετικός πίνακας ή το αναδυόμενο. Χρήσιμο για προ-συμπλήρωση πεδίων όταν δημιουργείτε νέα συνδεδεμένα αρχεία.
- required: Κάνει το πεδίο υποχρεωτικό. Η εγγραφή δεν σώζεται αν δεν είναι συμπληρωμένο.
- readonly: Αποτρέπει αλλαγές από χρήστη. Χρήσιμο όταν ο σύνδεσμος ορίζεται προγραμματιστικά και δεν πρέπει να αλλαχθεί χειροκίνητα.
- delegate: Όταν είναι True, όλα τα πεδία του σχετικού μοντέλου γίνονται απευθείας προσπελάσιμα από το τρέχον μοντέλο — χρησιμοποιείται κυρίως για την κλάση κληρονομικότητας μοντέλων, όχι για συνηθισμένες σχέσεις.
Πώς εμφανίζεται στις προβολές
Σε φόρμες, το Many2One δείχνει σαν dropdown με πεδίο αναζήτησης. Μπορείς να πληκτρολογήσεις μερικούς χαρακτήρες για να φιλτράρεις τα αποτελέσματα ή να ανοίξεις την εγγραφή με το βελάκι δίπλα στο πεδίο, κάνοντας τη μετάβαση μεταξύ σχετικών εγγράφων άμεση.
Σε λίστες, εμφανίζεται το όνομα της συνδεδεμένης εγγραφής και υποστηρίζει group-by: για παράδειγμα, ομαδοποίηση παραγγελιών κατά πελάτη ή εργασιών κατά έργο — λειτουργία που χρησιμοποιείται συχνά σε αναφορές.
Στις αναζητήσεις, τα Many2One λειτουργούν ως φίλτρα και ως κριτήρια group-by. Όταν φιλτράρεις την pipeline του CRM κατά πελάτη, στην πραγματικότητα φιλτράρεις πάνω σε ένα Many2One πεδίο.
Η αντίστροφη σχέση One2Many
Κάθε Many2One έχει φυσικά το αντίστροφο One2Many. Όταν οι παραγγελίες δείχνουν σε έναν πελάτη, ο πελάτης μπορεί να εμφανίζει όλες τις παραγγελίες του μέσω ενός One2Many πεδίου. Είναι καλή πρακτική να δηλώνεις και τις δύο πλευρές: αυτό επιτρέπει στους χρήστες να βλέπουν όλες τις σχετικές εγγραφές από τη φόρμα του πελάτη χωρίς να τρέχουν ξεχωριστές αναζητήσεις. Το One2Many δεν προσθέτει νέα στήλη στη βάση· υπολογίζεται από το foreign key του άλλου μοντέλου.
Επιχειρηματικά σενάρια χρήσης
Πέντε πρακτικά παραδείγματα
CRM: Σύνδεση leads με πωλητές
Στο CRM, κάθε lead έχει συνήθως ένα πεδίο user_id (Many2One προς res.users) που δείχνει τον υπεύθυνο πωλητή. Με αυτό οι διευθυντές φιλτράρουν pipeline ανά εκπρόσωπο, μετρούν ποσοστά μετατροπής ανά άτομο και αναθέτουν μαζικά leads. Αν χρειαστεί δεύτερος υπεύθυνος, απλώς προσθέτεις ένα ακόμη Many2One στο ίδιο μοντέλο χρηστών.
Πωλήσεις: Σύνδεση παραγγελιών με πελάτες και τιμοκαταλόγους
Μια παραγγελία περιλαμβάνει συνήθως partner_id (ποιος είναι ο πελάτης) και pricelist_id (ποια τιμολόγηση εφαρμόζεται). Όταν επιλέγεις πελάτη, το Odoo μπορεί να συμπληρώσει αυτόματα τιμοκατάλογο, όρους πληρωμής και διεύθυνση παράδοσης μέσω onchange μεθόδων που βασίζονται στο Many2One — προφανές πλεονέκτημα για ορθή και γρήγορη εισαγωγή δεδομένων.
Αποθήκη: Προϊόντα και Κατηγορίες
Κάθε προϊόν συνδέεται με κατηγορία προϊόντος μέσω Many2One (π.χ. categ_id στο product.template). Η κατηγορία καθορίζει λογιστικές λογαριασμούς, μεθόδους αποτίμησης και στρατηγικές αποθέματος. Σωστή κατηγοριοποίηση είναι κρίσιμη για σωστή χρηματοοικονομική εικόνα — ένα απλό dropdown Many2One κάνει τη δουλειά εύκολη και συνεπή.
Λογιστήριο: Λογιστικές εγγραφές και journals
Κάθε καταχώριση βιβλίου συνδέεται με ένα journal μέσω Journal_id. Το journal καθορίζει σειρές αρίθμησης, τύπο παραστατικού (πώληση, προμηθευτής, τράπεζα κ.λπ.) και μερικές φορές προεπιλεγμένους λογαριασμούς. Λανθασμένη επιλογή journal σημαίνει ότι τα δεδομένα πηγαίνουν σε λάθος τμήμα του γενικού καθολικού — το Many2One εδώ λειτουργεί ως σημείο ελέγχου για τη λογιστική ακρίβεια.
Διαχείριση έργου: Εργασίες και Έργα
Στο Project, κάθε εργασία ανήκει σε ένα έργο μέσω project_id. Αυτή η μονή σύνδεση καθορίζει τη ροή σταδίων, τα δικαιώματα πρόσβασης και τον τρόπο καταγραφής χρονοκαταγραφών. Για εταιρείες παροχής υπηρεσιών που τιμολογούν ανά έργο, η σχέση ανάμεσα σε timesheets, tasks και το parent project είναι ο σκελετός των ροών εσόδων και τιμολόγησης.
Δημιουργία ή προσαρμογή του Many2One πεδίου
Τρόποι προσθήκης Many2One πεδίου
Υπάρχουν τρεις βασικοί τρόποι για να προσθέσετε ένα Many2One, ανάλογα με το τεχνικό περιβάλλον και την προσέγγιση ανάπτυξης.
Χρήση Odoo Studio (χωρίς κώδικα)
- Το Odoo Studio είναι το εργαλείο low-code μέσα στην εφαρμογή. Για να προσθέσετε Many2One χωρίς κώδικα:
- Άνοιγμα του Odoo Studio από το κύριο μενού.
- Πήγαινε στη φόρμα όπου θες το πεδίο.
- Σύρε από την εργαλειοθήκη το Many2One πεδίο στη φόρμα.
- Στις ιδιότητες επέλεξε το στόχο μοντέλο και όρισε όνομα / domain αν χρειάζεται.
- Αποθήκευσε και κλείσε το Studio.
Το Studio δημιουργεί το πεδίο με πρόθεμα x_studio_ και το προσθέτει στη φόρμα. Το πεδίο λειτουργεί αμέσως: αναζητήσεις, dropdown και δημιουργία νέας σχετικής εγγραφής είναι διαθέσιμα. Είναι η πιο γρήγορη λύση για επιχειρήσεις που προτιμούν αλλαγές χωρίς ανάπτυξη κώδικα.
Χρήση Python σε προσαρμοσμένο module
Για developers, τα Many2One ορίζονται στο Python. Αυτή είναι η προτεινόμενη μέθοδος για παραγωγικά modules που χρειάζονται έλεγχο έκδοσης και περιβάλλοντα ανάπτυξης/παραγωγής.
from odoo import fields, models
class ProjectTask(models.Model):
_inherit = 'project.task'
x_client_contact_id = fields.Many2one(
comodel_name='res.partner',
string='Client Contact',
domain=[('type', '=', 'contact')],
ondelete='set null',
help='The main contact at the client for this task.',
)
Μετά τον ορισμό, προσθέτεις το πεδίο στο XML view και αναβαθμίζεις το module για να εφαρμοστούν οι αλλαγές στη βάση. Αυτή η προσέγγιση δίνει πλήρη έλεγχο σε domain, ondelete, compute methods και constraints — ιδανική για παραγωγικές υλοποιήσεις.
Καλό είναι να δηλώνεις και την αντίστροφη One2Many στο σχετικό μοντέλο ώστε η πλοήγηση να λειτουργεί και στις δύο κατευθύνσεις:
class ResPartner(models.Model):
_inherit = 'res.partner'
x_task_ids = fields.One2many(
comodel_name='project.task',
inverse_name='x_client_contact_id',
string='Related Tasks',
)
Χρήση XML-RPC API
Αν διαχειρίζεστε προγραμματιστικά το Odoo, π.χ. μέσω deployment script, μπορείτε να δημιουργήσετε πεδία Many2One με XML-RPC.
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_client_segment_id',
'field_description': 'Client Segment',
'model_id': model_id,
'ttype': 'many2one',
'relation': 'res.partner.category',
'on_delete': 'set null',
'state': 'manual',
}]
)
Το relation καθορίζει το στοχευόμενο μοντέλο και το on_delete τη συμπεριφορά διαγραφής. Όταν δημιουργείτε πεδία μέσω API, μην ξεχνάτε να φτιάχνετε και το αντίστροφο One2Many ώστε η πλοήγηση να λειτουργεί σωστά από τις δύο πλευρές.
Καλές πρακτικές
1. Πάντα φτιάχνετε την αντίστροφη One2Many
Όταν προσθέτετε ένα Many2One, δημιουργήστε και το αντίστοιχο One2Many στο σχετικό μοντέλο. Δεν προσθέτει στήλη στη βάση αλλά βελτιώνει την εμπειρία χρήστη: από τη φόρμα ενός πελάτη να βλέπεις άμεσα όλες τις σχετικές παραγγελίες ή εργασίες.
2. Χρησιμοποιήστε domain filters για περιορισμό επιλογών
Ένα Many2One προς res.partner ανοίγει προεπιλεγμένα όλους τους partners (πελάτες, προμηθευτές, εσωτερικές επαφές). Αν το πεδίο προορίζεται μόνο για πελάτες, ρυθμίστε domain όπως [('customer_rank','>',0)] για να μειώσετε τον «θόρυβο» και να αποφύγετε λάθος επιλογές.
3. Επιλέξτε προσεκτικά το ondelete
Το ondelete καθορίζει συμπεριφορές που μπορούν να έχουν σοβαρές συνέπειες. Το 'cascade' μπορεί να προκαλέσει απώλεια πολλών εγγραφών αν διαγράψετε την κύρια εγγραφή· συνήθως το 'set null' είναι ασφαλέστερο. Το 'restrict' χρησιμοποιείται όταν η συνδεδεμένη εγγραφή δεν πρέπει να διαγράφεται όσο υπάρχουν εξαρτήσεις.
4. Αποφύγετε την επανάληψη δεδομένων που πρέπει να είναι Many2One
Συχνό λάθος είναι να δημιουργείται πεδίο τύπου char για να αποθηκευτεί όνομα εταιρείας ή κατηγορία, αντί να δείχνει σε υπάρχοντα record. Η λύση Many2One αποφεύγει την αναπαραγωγή δεδομένων, διευκολύνει φιλτραρίσματα και συγκεντρωτικές αναφορές και διασφαλίζει συνέπεια όταν αλλάζουν ονόματα.
5. Χρησιμοποιήστε context για προ-συμπλήρωση όταν δημιουργούνται σχετικές εγγραφές
Μέσω του context μπορείτε να περάσετε προεπιλεγμένες τιμές όταν οι χρήστες δημιουργούν ένα νέο συνδεδεμένο record από το dropdown — για παράδειγμα, να γεμίσετε την τιμή του project αυτόματα σε μια νέα επαφή. Αυτό μειώνει χειρωνακτική εισαγωγή και διατηρεί συνέπεια στα δεδομένα.
Συνηθισμένα λάθη
Ξεχασμένη αντίστροφη One2Many
Η πιο συνηθισμένη παράλειψη είναι να προστεθεί فقط το Many2One χωρίς το αντίστοιχο One2Many. Το αποτέλεσμα είναι μονομερής σχέση: βλέπεις από τη μία πλευρά τον σύνδεσμο αλλά από την άλλη δεν μπορείς να βρεις όλες τις συνδεδεμένες εγγραφές — και σύντομα οι χρήστες θα ζητήσουν επιπλέον αναφορές ή φίλτρα για να καλύψουν το κενό.
Χρήση cascade διαγραφής χωρίς προσοχή
Όταν ορίζετε ondelete='cascade' για σχέσεις που συνδέουν λειτουργικά δεδομένα με κύριες εγγραφές, υπάρχει σοβαρός κίνδυνος απώλειας δεδομένων. Αν μια κατηγορία προϊόντων διαγραφεί και όλα τα προϊόντα έχουν cascade, χάνετε ολόκληρη την κατηγορία προϊόντων. Συνήθως προτιμάται set null ή restrict για επιχειρησιακά δεδομένα.
Μη έλεγχος για κενές τιμές στην Python πλοήγηση
Αν ένα Many2One είναι κενό, στο Python επιστρέφεται κενό recordset, που είναι falsy. Η έκφραση order.partner_id.name χωρίς έλεγχο μπορεί να δώσει κενό string. Αν πηγαίνετε βαθύτερα (order.partner_id.country_id.name) και κάποιο ενδιάμεσο είναι κενό, το αποτέλεσμα μπορεί να είναι κενό string και να παράγει σιωπηλά λάθη σε αναφορές ή email. Έλεγχος ύπαρξης είναι απαραίτητος όταν το πεδίο δεν είναι υποχρεωτικό.
Διεύθυνση προς λάθος μοντέλο
Το res.partner χρησιμοποιείται για πελάτες, προμηθευτές, επαφές και εταιρείες. Ένα Many2One προς res.partner χωρίς domain επιτρέπει όλα τα παραπάνω — αν το πεδίο προορίζεται για πελάτες, προσθέστε domain για να αποφύγετε εμφάνιση εσωτερικών χρηστών, διευθύνσεων παράδοσης ή προμηθευτών στο dropdown.
Κακή χρήση Many2One αντί για Selection
Αν οι επιλογές είναι λίγες και σταθερές, ένα Selection πεδίο είναι απλούστερο και πιο αποδοτικό από ένα Many2One. Τα Many2One απαιτούν ξεχωριστό μοντέλο και join στη βάση. Για πεδία όπως κατάσταση με 3–4 επιλογές, το Selection είναι συνήθως καλύτερο. Χρησιμοποιήστε Many2One όταν οι τιμές είναι πολλές, διαχειρίζονται από χρήστες ή μοιράζονται μεταξύ πολλών μοντέλων.
Συμπέρασμα
Το Many2One είναι ο πυρήνας του τρόπου που το Odoo συνδέει δεδομένα μεταξύ modules. Η κατανόησή του δεν αφορά μόνο προγραμματιστές — αναλυτές, functional consultants και power users που χρησιμοποιούν Studio κερδίζουν πολύ, γνωρίζοντας πότε και πώς να προσθέτουν τέτοιες σχέσεις.
Σημεία-κλειδιά: πάντα δημιουργείτε και την αντίθετη One2Many για πλήρη πλοήγηση, χρησιμοποιείτε domain για καθαρά dropdown, επιλέγετε προσεκτικά ondelete και αποφεύγετε Many2One όπου ένα Selection αρκεί.
Είτε ρυθμίζετε πεδία με Studio, είτε γράφετε custom module σε Python, είτε χειρίζεστε το μοντέλο μέσω API, οι σωστές σχέσεις από την αρχή κάνουν την υλοποίηση πιο αξιόπιστη και ευκολότερη στη συντήρηση.
Στη Dasolo υποστηρίζουμε εταιρείες στην υλοποίηση, προσαρμογή και βελτιστοποίηση του Odoo σε όλες τις ομάδες. Είτε χρειάζεστε βοήθεια στο σχεδιασμό καθαρού μοντέλου δεδομένων, στην προσθήκη σχετικών πεδίων στις φόρμες ή στην κατασκευή πλήρους module, η ομάδα μας μπορεί να σας υποστηρίξει. Επικοινωνήστε μαζί μας και να συζητήσουμε το Odoo project σας.