Εισαγωγή
Αν έχετε ανοίξει ποτέ μια Παραγγελία Πώλησης στο Odoo και είδατε τη λίστα με τις γραμμές παραγγελίας μέσα στη φόρμα, τότε έχετε ήδη δει το One2many σε δράση. Είναι ένα από τα πιο συχνά χρησιμοποιούμενα στοιχεία του μοντέλου δεδομένων του Odoo και αξίζει να το γνωρίζετε καλά, είτε διαχειρίζεστε το σύστημα είτε αναπτύσσετε πάνω του.
Αυτό το άρθρο εξηγεί με πρακτικό τρόπο τι ακριβώς κάνει το One2many, πώς το χειρίζεται το ORM του Odoo, πότε είναι η κατάλληλη επιλογή για τη δική σας ρύθμιση και πώς να το προσθέσετε είτε μέσω Studio είτε γράφοντας κώδικα Python.
Είτε είστε χρήστης που θέλει να καταλάβει τη δομή των δεδομένων, είτε προγραμματιστής που χρειάζεται έναν απλό οδηγό για τα πεδία του Odoo, εδώ θα βρείτε τις βασικές πληροφορίες που χρειάζεστε.
Τι είναι το πεδίο One2many στο Odoo
Το One2many είναι ένας τύπος σχεσιακού πεδίου στο Odoo που επιτρέπει σε μία εγγραφή «γονέα» να συνδέεται με πολλές εγγραφές «παιδιού» από άλλο μοντέλο.
Σκεφτείτε το σαν μια μητρική εγγραφή που συγκεντρώνει μικρότερες εγγραφές: μια εταιρεία με πολλούς υπαλλήλους, μια παραγγελία με πολλές γραμμές, ή ένα έργο με πολλές εργασίες. Το One2many λειτουργεί ως η συλλογή που εμφανίζει όλα τα σχετικά παιδικά στοιχεία.
Στο περιβάλλον χρήστη του Odoo, το One2many συνήθως εμφανίζεται ως ενσωματωμένη λίστα μέσα σε μια φόρμα. Αυτή η μικρή «πίνακας μέσα στη φόρμα» επιτρέπει στους χρήστες να προσθέτουν, να επεξεργάζονται ή να διαγράφουν τα παιδικά στοιχεία χωρίς να αλλάζουν οθόνη, κάτι που βελτιώνει την ευχρηστία σε καθημερινές ροές εργασίας.
Πώς ξεχωρίζει από άλλα σχεσιακά πεδία
Στο Odoo υπάρχουν τρεις βασικοί τύποι σχεσιακών πεδίων στο ORM:
- Many2one: Μια εγγραφή που δείχνει σε μια εγγραφή άλλου μοντέλου (π.χ. μια παραγγελία σε έναν πελάτη).
- One2many: Μια εγγραφή γονέα που συνδέεται με πολλές εγγραφές παιδιού (π.χ. παραγγελία με γραμμές παραγγελίας).
- Many2many: Πολλές εγγραφές και από τις δύο πλευρές συνδέονται μεταξύ τους (π.χ. προϊόντα που έχουν πολλές ετικέτες και ετικέτες που ανήκουν σε πολλά προϊόντα).
Το One2many εφαρμόζεται όταν κάθε παιδί ανήκει αποκλειστικά σε έναν γονέα. Αν ένα παιδί χρειάζεται να συνδέεται ταυτόχρονα με πολλούς γονείς, τότε το σωστό εργαλείο είναι το Many2many.
Μια ιδιαιτερότητα του One2many είναι ότι το ίδιο το πεδίο δεν αποθηκεύει δεδομένα στον πίνακα του γονέα — είναι ένα εικονικό πεδίο που διαβάζει τα δεδομένα από το παιδικό μοντέλο μέσω ενός Many2one στο παιδί.
Πώς λειτουργεί το πεδίο
Σε επίπεδο βάσης δεδομένων, δεν υπάρχει στήλη στον πίνακα του γονέα για το One2many. Αντιθέτως, κάθε εγγραφή του παιδιού έχει μια ξένη κλείδα (foreign key) που δείχνει στον γονέα.
Αυτό το μοτίβο είναι θεμελιώδες στο ORM του Odoo: κάθε One2many υποστηρίζεται από ένα αντίστοιχο Many2one στο σχετικό μοντέλο. Το One2many απλώς αναζητά όλα τα παιδικά όπου το Many2one δείχνει στον τρέχοντα γονέα.
Η σχέση μεταξύ One2many και Many2one
Κατά τον ορισμό ενός One2many σε Python, χρειάζονται δύο βασικές παραμέτροι:
- comodel_name: το μοντέλο που περιέχει τις παιδικές εγγραφές.
- inverse_name: το όνομα του πεδίου Many2one στο παιδικό μοντέλο που δείχνει πίσω στον γονέα.
Για παράδειγμα, σε ένα προσαρμοσμένο module που συνδέει ένα συμβόλαιο με παραδοτέα, ορίζετε το One2many στο μοντέλο του συμβολαίου και ένα Many2one στο μοντέλο των παραδοτέων.
deliverable_ids = fields.One2many(
comodel_name='service.deliverable',
inverse_name='contract_id',
string='Deliverables'
)
Στο παράδειγμα, το contract_id είναι το Many2one στο service.deliverable. Χωρίς αυτό το πεδίο στο παιδί, το One2many δεν μπορεί να λειτουργήσει.
Τι συμβαίνει στη βάση δεδομένων
Τα δεδομένα που ανήκουν σε ένα One2many αποθηκεύονται στον πίνακα του παιδιού: κάθε γραμμή περιέχει την ξένη κλείδα που δείχνει τον γονέα.
Όταν το Odoo φορτώνει τον γονέα και πρέπει να εμφανίσει το One2many, εκτελεί ένα ερώτημα για να βρει όλες τις εγγραφές του παιδιού όπου το foreign key αντιστοιχεί στο ID του γονέα. Το ORM αναλαμβάνει αυτόματα αυτή τη διαδικασία.
Γι' αυτό το One2many θεωρείται πεδίο που δεν προσθέτει κολώνα στη βάση δεδομένων του γονέα — είναι απλώς μια προβολή των σχετιζόμενων εγγραφών.
Επιχειρηματικά σενάρια χρήσης
Το One2many εμφανίζεται σε πολλές περιοχές του Odoo επειδή μοντελοποιεί φυσικά σχέσεις γονέα–παιδιού. Ακολουθούν πέντε πρακτικά παραδείγματα από πραγματικές επιχειρησιακές ροές.
1. Παραγγελίες Πώλησης και Γραμμές Παραγγελίας
Στο module Πωλήσεων, το πεδίο order_line_ids στο sale.order συνδέει τις γραμμές παραγγελίας sale.order.line. Κάθε γραμμή περιέχει προϊόν, ποσότητα, τιμή μονάδας και έκπτωση, και οι χρήστες μπορούν να τις διαχειρίζονται απευθείας μέσα στη φόρμα της παραγγελίας.
2. Τιμολόγια και Γραμμές Τιμολογίου
Στην Λογιστική, το account.move χρησιμοποιεί One2many πεδίο για να κρατήσει τις γραμμές τιμολογίου (account.move.line), όπου κάθε γραμμή αντιπροσωπεύει χρέωση για προϊόν ή υπηρεσία και τα συνολικά αθροίζονται στον γονέα.
3. Έργα και Εργασίες
Στο module Project, το One2many στο project.project εμφανίζει όλες τις εργασίες που ανήκουν στο έργο. Η ίδια σχέση μπορεί να οδηγήσει σε λίστα, kanban ή Gantt, ανάλογα με την προβολή που επιλέγεται.
4. Επαφές και Υπο-επαφές
Το res.partner διαθέτει το πεδίο child_ids που εμφανίζει όλα τα άτομα συνδεδεμένα με μια εταιρεία. Κάθε υπο-επαφή έχει Many2one parent_id που δείχνει στην εταιρεία.
5. Προσαρμοσμένα μοντέλα σε Υπηρεσίες ή Παραγωγή
Κατά την κατασκευή custom module, το One2many είναι η φυσική επιλογή όταν μία εγγραφή 'κατέχει' έναν κατάλογο υπο-εγγραφών — π.χ. αίτημα συντήρησης με πολλά ανταλλακτικά, εκπαιδευτικό μάθημα με πολλές ημερομηνίες συνεδριών ή συμβόλαιο υπηρεσιών με πολλαπλά παραδοτέα.
Η ευελιξία αυτή είναι λόγος που το One2many είναι κεντρικό εργαλείο στην προσαρμογή του Odoo για διάφορες βιομηχανίες.
Δημιουργία ή προσαρμογή του πεδίου
Υπάρχουν δύο κύριοι τρόποι για να προσθέσετε ένα One2many: χωρίς κώδικα μέσω Odoo Studio ή με κώδικα σε custom module.
Χρήση του Odoo Studio
Στο Studio δεν μπορείτε απευθείας να δημιουργήσετε One2many από τον επιλογέα πεδίων του γονέα, επειδή το One2many απαιτεί να υπάρχει πρώτα ένα Many2one στο παιδικό μοντέλο.
Η συνιστώμενη διαδικασία στο Studio είναι:
- Ανοίξτε το μοντέλο του παιδιού στο Studio και προσθέστε ένα πεδίο Many2one που δείχνει στον γονέα.
- Αφού αποθηκευτεί, επιστρέψτε στο μοντέλο του γονέα στο Studio.
- Προσθέστε νέο πεδίο επιλέγοντας One2many — το Studio θα ζητήσει να επιλέξετε το σχετικό μοντέλο και το inverse Many2one πεδίο.
- Το One2many θα εμφανιστεί ως ενσωματωμένη λίστα στη φόρμα του γονέα.
Για πολλούς χρήστες επιχειρήσεων, αυτή είναι η απλούστερη μέθοδος για να δημιουργήσουν σχέσεις One2many χωρίς να γράψουν κώδικα. Τα πεδία που φτιάχνονται έτσι συμπεριφέρονται όπως τα αντίστοιχα Python πεδία.
Χρήση κώδικα Python σε custom module
Οι προγραμματιστές προτιμούν να ορίζουν One2many σε Python για πλήρη έλεγχο της συμπεριφοράς, των ονομάτων και των domain φίλτρων. Ένα τυπικό παράδειγμα δείχνει την δομή των δύο μοντέλων.
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)
Σημειώστε ότι το Many2one (contract_id) ορίζεται πρώτα στο παιδί. Το inverse_name στην One2many πρέπει να ταιριάζει ακριβώς με το όνομα του Many2one.
Δημιουργία του πεδίου μέσω XML-RPC API
Αν διαχειρίζεστε πεδία προγραμματιστικά, μπορείτε να δημιουργήσετε One2many μέσω του XML-RPC χρησιμοποιώντας το μοντέλο ir.model.fields. Και εδώ ισχύει ο ίδιος κανόνας: φτιάχνετε πρώτα το Many2one και μετά το One2many με το relation_field που δείχνει στο όνομα του Many2one.
Αυτή η μέθοδος είναι χρήσιμη όταν αυτοματοποιείτε αλλαγές σε πολλαπλά περιβάλλοντα ή έχετε διαδικασίες provisioning των πεδίων.
Καλές πρακτικές
Από την εμπειρία υλοποίησης Odoo σε διάφορους πελάτες, οι παρακάτω πρακτικές κάνουν πραγματική διαφορά όταν δουλεύετε με One2many.
- Δημιουργήστε πάντα πρώτα το Many2one. Το One2many δεν μπορεί να υπάρξει χωρίς το αντίστροφο πεδίο. Είτε στο Studio, είτε σε Python, είτε μέσω API, φροντίστε να υπάρχει το Many2one στο παιδί πριν ορίσετε το One2many.
- Χρησιμοποιήστε το επίθημα
_idsστα ονόματα. Συμβατικά, τα One2many ονομάζονται με_ids(π.χ.line_ids,task_ids) ώστε να είναι προφανές ότι επιστρέφουν σύνολο εγγραφών. - Ορίστε
ondelete='cascade'όταν χρειάζεται. Αν θέλετε τα παιδικά να διαγράφονται μαζί με τον γονέα, βάλτε την επιλογή αυτή στο Many2one ώστε να αποφύγετε ορφανά δεδομένα. - Διατηρήστε τη λίστα εστιασμένη. Εμφανίστε μόνο τις πιο σημαντικές στήλες στο One2many. Πολλές στήλες κάνουν τη φόρμα αργή και δύσχρηστη — χρησιμοποιήστε το attribute
optionalγια δευτερεύουσες στήλες που ο χρήστης μπορεί να ενεργοποιήσει. - Χρησιμοποιήστε domain φίλτρα για περιορισμό. Προσθέστε
domainστη One2many για να φιλτράρετε ποια παιδικά εμφανίζονται, ειδικά αν το ίδιο παιδικό μοντέλο μοιράζεται ανάμεσα σε πολλούς γονείς. - Προσοχή σε μεγάλα σύνολα δεδομένων. Αν ένας γονέας μπορεί να έχει χιλιάδες παιδικά, αποφύγετε να τα φορτώνετε όλα ταυτόχρονα στη φόρμα. Σκεφτείτε ξεχωριστή λίστα, pagination ή περιορισμό με
limit.
Συνηθισμένα λάθη
Παρακάτω βρίσκονται τα πιο συνηθισμένα λάθη που εμφανίζονται όταν δουλεύετε με One2many, είτε σε ανάπτυξη είτε σε ρύθμιση.
Παραγνώριση του Many2one ως αντίστροφου
Το πιο συνηθισμένο σφάλμα είναι να οριστεί One2many χωρίς να υπάρχει το αντίστοιχο Many2one στο παιδί. Το Odoo θα πετάξει σφάλμα. Ελέγξτε πάντα ότι το inverse_name υπάρχει όντως στο παιδικό μοντέλο.
Λανθασμένη σύνταξη στο write
Για να ενημερώσετε ένα One2many μέσω Python ή API πρέπει να χρησιμοποιήσετε τη σύνταξη εντολών του Odoo (command tuples). Δεν μπορείτε να αντιστοιχίσετε απλά μια Python λίστα στο πεδίο.
(0, 0, values_dict)για δημιουργία νέας παιδικής εγγραφής.(1, child_id, values_dict)για ενημέρωση υπάρχουσας παιδικής εγγραφής.(2, child_id, 0)για διαγραφή υπάρχουσας παιδικής εγγραφής.(4, child_id, 0)για προσθήκη υπάρχουσας παιδικής εγγραφής στη σχέση.(5, 0, 0)για αποσύνδεση όλων των παιδικών από τον γονέα (χωρίς διαγραφή).
Η προσπάθεια να γράψετε απλά record.line_ids = [1, 2, 3] δεν θα λειτουργήσει όπως περιμένετε στο ORM του Odoo.
Σύγχυση One2many με Many2many
Το One2many υποδηλώνει ότι κάθε παιδί ανήκει σε έναν μόνο γονέα. Αν χρειάζεται να συνδέσετε την ίδια εγγραφή με πολλούς γονείς, χρησιμοποιήστε Many2many — το One2many σε αυτή την περίπτωση θα αναγκάσει διπλασιασμούς και θα οδηγήσει σε προβλήματα ακεραιότητας δεδομένων.
Προβλήματα απόδοσης με μεγάλες υπολίστες
Αν ένα One2many εμφανίζει εκατοντάδες ή χιλιάδες γραμμές μέσα σε μια φόρμα, η φόρτωση γίνεται αργή. Αυτό εμφανίζεται συχνά σε τιμολόγια ή κινήσεις αποθέματος. Χρησιμοποιήστε περιορισμό (limit) στη λίστα ή προώθηση σε ξεχωριστή προβολή για μεγάλα σετ.
Ορφανά δεδομένα μετά από διαγραφή
Αν διαγράψετε τον γονέα χωρίς να έχετε ορίσει ondelete='cascade' στο Many2one, τα παιδικά μπορεί να μείνουν με κενή ή άκυρη αναφορά. Με τον καιρό αυτά τα ορφανά δεδομένα μπορούν να γεμίσουν τη βάση και να προκαλέσουν περίεργες συμπεριφορές. Ορίστε σαφή πολιτική διαγραφής στον σχεδιασμό του μοντέλου.
Συμπέρασμα
Το One2many είναι θεμελιώδες κομμάτι του ORM και του μοντέλου δεδομένων του Odoo. Κινεί βασικές λειτουργίες της πλατφόρμας — από γραμμές παραγγελιών μέχρι γραμμές τιμολογίων και εργασίες έργου. Μόλις καταλάβετε τη σχέση του με το Many2one, μεγάλο μέρος της εσωτερικής δομής του Odoo γίνεται πολύ πιο κατανοητό και εύκολο στην επέκταση.
Είτε ρυθμίζετε το Odoo για την επιχείρησή σας, είτε το προσαρμόζετε με Studio, είτε δημιουργείτε custom modules, το One2many θα είναι ένα εργαλείο που θα χρησιμοποιήσετε συχνά. Η σωστή χρήση του και η αποφυγή των βασικών λαθών θα σας γλιτώσουν χρόνο και προβλήματα στα δεδομένα.
Αν θέλετε περισσότερους τεχνικούς οδηγούς για πεδία και API του Odoo, εξερευνήστε τα υπόλοιπα άρθρα της συλλογής Odoo Data & API.
Χρειάζεστε βοήθεια με την υλοποίηση του Odoo;
Η Dasolo βοηθά εταιρείες να υλοποιήσουν, να προσαρμόσουν και να βελτιστοποιήσουν το Odoo ώστε να ταιριάζει στις ανάγκες τους. Είτε χρειάζεστε βοήθεια στο σχεδιασμό του μοντέλου δεδομένων, στην ανάπτυξη custom modules, στη δημιουργία πεδίων ή στην αξιοποίηση του υπάρχοντος συστήματος, η ομάδα μας μπορεί να αναλάβει.
Αν έχετε απορίες για το έργο Odoo ή θέλετε να συζητήσετε την καλύτερη δομή για τα δεδομένα σας, επικοινωνήστε μαζί μας. Θα χαρούμε να βοηθήσουμε.