
Adding data fields to a model
Models are meant to store data, and this data is structured in fields. Here, we will learn about the several types of data that can be stored in fields, and how to add them to a model.
Getting ready
This recipe assumes that you have an instance ready with the my_module
addon module available, as described in Chapter 3, Creating Odoo Modules.
How to do it…
The my_module
addon module should already have a models/library_book.py
defining a basic Model. We will edit it to add new fields:
- Use the minimal syntax to add fields to the Library Books model:
from openerp import models, fields class LibraryBook(models.Model): # ... short_name = fields.Char('Short Title') notes = fields.Text('Internal Notes') state = fields.Selection( [('draft', 'Not Available'), ('available', 'Available'), ('lost', 'Lost')], 'State') description = fields.Html('Description') cover = fields.Binary('Book Cover') out_of_print = fields.Boolean('Out of Print?') date_release = fields.Date('Release Date') date_updated = fields.Datetime('Last Updated') pages = fields.Integer('Number of Pages') reader_rating = fields.Float( 'Reader Average Rating', (14, 4), # Optional precision (total, decimals), )
- All these fields support a few common attributes. As an example, we could edit the preceding
pages
field to add them:pages = fields.Integer( string='Number of Pages', default=0, help='Total book page count', groups='base.group_user', states={'cancel': [('readonly', True)]}, copy=True, index=False, readonly=False, required=False, company_dependent=False, )
- The
Char
fields support a few specific attributes. As an example, we can edit theshort_name
field to add them:short_name = fields.Char( string='Short Title', size=100, # For Char only translate=False, # also for Text fields )
- The HTML fields also have specific attributes:
description = fields.Html( string='Description', # optional: sanitize=True, strip_style=False, translate=False, )
Upgrading the module will make these changes effective in the Odoo model.
How it works…
Fields are added to models by defining an attribute in its Python class. The non-relational field types available are as follows:
Char
for string values.Text
for multi-line string values.Selection
for selection lists. This has a list of values and description pairs. The value that is selected is what gets stored in the database, and it can be a string or an integer.Html
is similar to the Text field, but is expected to store rich text in the HTML format.Binary
fields store binary files, such as images or documents.Boolean
storesTrue
/False
values.Date
stores date values. The ORM handles them in the string format, but they are stored in the database as dates. The format used is defined inopenerp.fields.DATE_FORMAT
.Datetime
for date-time values. They are stored in the database in a naive date time, in UTC time. The ORM represents them as a string and also in UTC time. The format used is defined inopenerp.fields.DATETIME_FORMAT
.Integer
fields need no further explanation.Float
fields store numeric values. The precision can optionally be defined with a total number of digits and decimal digits pairs.Monetary
can store an amount in a certain currency; it is also explained in another recipe.
The first step in the recipe shows the minimal syntax to add each field type. The field definitions can be expanded to add other optional attributes, as shown in step 2.
Here is an explanation for the field attributes used:
string
is the field's title, used in UI view labels. It actually is optional; if not set, a label will be derived from the field name by adding title case and replacing underscores with spaces.size
only applies toChar
fields and is the maximum number of characters allowed. In general, it is advised not to use it.translate
when set toTrue
, makes the field translatable; it can hold a different value depending on the user interface language.default
is the default value. It can also be a function that is used to calculate the default value. For example,default=_compute_default
, where_compute_default
is a method defined on the model before the field definition.help
is an explanation text displayed in the UI tooltips.groups
makes the field available only to some security groups. It is a string containing a comma-separated list of XML IDs for security groups. This is addressed in more detail in Chapter 10, Access Security.states
allows the user interface to dynamically set the value for thereadonly
,required
, andinvisible
attributes, depending on the value of thestate
field. Therefore, it requires astate
field to exist and be used in the form view (even if it is invisible).copy
flags if the field value is copied when the record is duplicated. By default, it isTrue
for non-relational andMany2one
fields andFalse
forOne2many
and computed fields.index
, when set toTrue
, makes for the creation of a database index for the field, allowing faster searches. It replaces the deprecatedselect=1
attribute.- The
readonly
flag makes the field read-only by default in the user interface. - The
required
flag makes the field mandatory by default in the user interface. - The
sanitize
flag is used by HTML fields and strips its content from potentially insecure tags. strip_style
is also an HTML field attribute and has the sanitization to also remove style elements.- The
company_dependent
flag makes the field store different values per company. It replaces the deprecatedProperty
field type.
There's more…
The Selection
field also accepts a function reference instead of a list, as its "selection" attribute. This allows for dynamically generated lists of options. You can see an example of this in the Add dynamic relations using Reference fields recipe, where a selection attribute is also used.
The Date
and Datetime
field objects expose a few utility methods that can be convenient.
For Date
, we have the following:
fields.Date.from_string(string_value)
parses the string into a date object.fields.Date.to_string(date_value)
represents theDate
object as a string.fields.Date.today()
returns the current day in string format.fields.Date.context_today(record)
returns the current day in string format according to the timezone of the record's (or recordset) context.
For Datetime
, we have the following:
fields.Datetime,from_string(string_value)
parses the string into adatetime
object.fields.Datetime,to_string(datetime_value)
represents thedatetime
object as a string.fields.Datetime,now()
returns the current day and time in string format. This is appropriate to use for default values.fields.Datetime,context_timestamp(record, value)
converts avalue
naive date-time into a timezone-aware date-time using the timezone in the context ofrecord
. This is not suitable for default values.
Other than basic fields, we also have relational fields: Many2one
, One2many
, and Many2many
. These are explained in the Add relational fields to a model recipe.
It's also possible to have fields with automatically computed values, defining the computation function with the compute
field attribute. This is explained in the Adding computed fields to a model recipe.
A few fields are added by default in Odoo models, so we should not use these names for our fields. These are the id
field, for the record's automatically generated identifier, and a few audit log fields, which are as follows:
create_date
is the record creation timestampcreate_uid
is the user that created the recordwrite_date
is the last recorded edit timestampwrite_uid
is the user that last edited the record
The automatic creation of these log fields can be disabled by setting the _log_access=False
model attribute.
Another special column that can be added to a model is active
. It should be a Boolean flag allowing for mark records as inactive. Its definition looks like this:
active = fields.Boolean('Active', default=True)
By default, only records with active
set to True
are visible. To have them retrieved, we need to use a domain filter with [('active', '=', False)]
. Alternatively, if the 'active_test': False
value is added to the environment Context, the ORM will not filter out inactive records.