Creating the data model
The Odoo development guidelines state that the Python files for models should be placed inside a models subdirectory, and we should have one file for each model. So, we will create a models/library_book.py file in the main directory of the library_app module.
Before that, we need to let Python know that the models directory should be used (imported in Python jargon). To do that, edit the module's main __init__.py file, like this:
from . import models
To import the Python code file to be used, we need to add a models/__init__.py file:
from . import library_book
Now we can create the models/library_book.py file with the following content:
from odoo import fields, models
class Book(models.Model): _name = 'library.book' _description = 'Book' name = fields.Char('Title', required=True)
isbn = fields.Char('ISBN')
active = fields.Boolean('Active?', default=True)
date_published = fields.Date()
image = fields.Binary('Cover')
publisher_id = fields.Many2one('res.partner', string='Publisher')
author_ids = fields.Many2many('res.partner', string='Authors')
The first line is a Python code import statement, making the models and fields objects from the Odoo core available.
The second line declares our new model. It's a Python class derived from models.Model.
The next line sets the _name attribute, defining the identifier that will be used throughout Odoo to refer to this model. Note that the actual Python class name, Book, is irrelevant for the Odoo framework. The _name value is what will be used as the model identifier.
Notice that this and the following lines are indented. If you're not familiar with Python, you should know that this is important—indentation defines a nested code block, so these four lines should all be equally indented.
Then we have the _description model attribute. It is not mandatory, but it provides a user-friendly name for the model records, which can be used for better user messages.
The remaining lines define the model's fields. It's worth noting that name and active are special field names. By default, Odoo will use the name field as the record's title when referencing it from other models.
The active field is used to activate records, and by default, only active records will be shown. This is useful for master date models, to hide away records that are no longer used in daily operations by users—for historical reasons, they need to be kept in the database. In our case, it will allow us to signal the books available in our library, and the ones no longer available.
We can see examples of other field types—date_published is a date field, for the book's publication date, and image is a binary field, to store the book's cover image.
We can see also examples of relation fields—the publisher_id field, which is a many-to-one relation for the publishing company, and author_ids, a many-to-many relation for the list of authors.
Both are relations between the book and the partner model. The partner model is built into the Odoo framework, and is where people, companies, and addresses should be stored. We are using it to store our list of publishers and authors.
That's it! For our Python code changes to take effect, the module needs to be upgraded, triggering the creation of the corresponding objects in the database.
We won't see any menu options to access this new model, since we haven't added them yet. Still, we can inspect the newly-created model using the Technical menu. In the Settings top menu, go to Technical | Database Structure | Models, search for the library.book model in the list, and click on it to see its definition:
If everything goes well, it will be confirmed that the model and fields were created. If you can't see them here, try a server restart with a module upgrade.
We can also see some additional fields that we didn't declare. These are reserved fields that Odoo automatically adds to every new model. They are as follows:
- id is a unique numeric identifier for each record in the model.
- create_date and create_uid specify when the record was created and who created it, respectively.
- display_name provides a textual representation for the record used, for example, when it is referenced in other records. It is computed and, by default, uses the text in the name field.
- write_date and write_uid confirm when the record was last modified and who modified it, respectively.
- __last_update is a helper that is not actually stored in the database. It is used for concurrency checks.