After creating a new model, the next step is to add fields to it. Odoo supports all the basic data types expected, such as text strings, integers, floating point numbers, Booleans, dates, datetimes, and image/binary data.

Some field names are special, wither because they are reserved by the ORM for special purposes, or because some built-in features by default use some default field names.

Let's explore the several types of fields available in Odoo.

We now have a Stage model and we will expand it to add some additional fields. We should edit the todo_ui/models/todo_model.py file and add extra field definitions to make it look like this:

class Stage(models.Model): 
    _name = 'todo.task.stage' 
    _description = 'To-do Stage' 
    _order = 'sequence,name' 
    # String fields: 
    name = fields.Char('Name', 40) 
    desc = fields.Text('Description') 
    state = fields.Selection( 
        [('draft','New'), ('open','Started'),
        ('done','Closed')],'State') 
    docs = fields.Html('Documentation') 
    # Numeric fields: 
    sequence = fields.Integer('Sequence') 
    perc_complete = fields.Float('% Complete', (3, 2)) 
    # Date fields: 
    date_effective = fields.Date('Effective Date') 
    date_changed = fields.Datetime('Last Changed') 
    # Other fields: 
    fold = fields.Boolean('Folded?') 
    image = fields.Binary('Image') 

Here, we have a sample of the non-relational field types available in Odoo with the positional arguments expected by each one.

In most cases, the first argument is the field title, corresponding to the string field argument; this is used as the default text for the user interface labels. It's optional, and if not provided, a title will be automatically generated from the field name.

For date field names, there is a convention to use date as a prefix. For example, we should use date_effective field instead of effective_date. Similar conventions also apply to other fields, such as amount_, price_, or qty_.

These are the standard positional arguments expected by each of the field types:

Other than these, we also have the relational fields, which will be introduced later in this chapter. But now, there is still more to learn about these field types and their attributes.

Fields have attributes that can be set when defining them. Depending on the field type, a few attributes can be passed positionally, without an argument keyword, as shown in the previous section.

For example, name=fields.Char('Name', 40) could make use of positional arguments. Using the keyword arguments, the same could be written as name=fields.Char(size=40, string='Name'). More information on keyword arguments can be found in the Python official documentation at https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments .

All the available attributes can be passed as a keyword argument. These are the generally available attributes and the corresponding argument keywords:

  • string is the field default label, to be used in the user interface. Except for selection and relational fields, it is the first positional argument, so most of the time it is not used as a keyword argument.
  • default sets a default value for the field. It can be a static value, such as a string, or a callable reference, either a named function or an anonymous function (a lambda expression).
  • size applies only to Char fields, and can set a maximum size allowed. Current best practice is to not use it unless it's really needed.
  • translate applies only to Char, Text, and Html fields, and makes the field contents translatable, holding different values for different languages.
  • help provides the text for tooltips displayed to the users.
  • readonly=True makes the field by default not editable on the user interface. This is not enforced at the API level; it is only a user interface setting.
  • required=True makes the field by default mandatory in the user interface. This is enforced at the database level by adding a NOT NULL constraint on the column.
  • index=True will create a database index on the field.
  • copy=False has the field ignored when using the duplicate record feature, copy() ORM method. The non-relational fields are copyable by default.
  • groups allows limiting the field's access and visibility to only some groups. It expects a comma separated list of XML IDs for security groups, such as groups='base.group_user,base.group_system'.
  • states expects a dictionary mapping values for UI attributes depending on values of the state field. For example: states={'done':[('readonly',True)]}. Attributes that can be used are readonly, required, and invisible.

For completeness, two other attributes are sometimes used when upgrading between Odoo major versions:

A few field names are reserved to be used by the ORM.

The id field is an automatic number uniquely identifying each record, and used as the database primary key. It's automatically added to every model.

The following fields are automatically created on new models, unless the _log_access=False model attribute is set:

This information is available from the web client, navigating to the Developer Mode menu and selecting the View Metadata option.

Some API built-in features by default expect specific field names. We should avoid using these field names for purposes other than the intended ones. Some of them are even reserved and can't be used for other purposes at all:

So far, we've discussed non-relational fields. But a good part of an application data structure is about describing the relationships between entities. Let's look at that now.