Now fields are class property:
from openerp import models, fields class AModel(models.Model): _name = 'a_name' name = fields.Char( string="Name", # Optional label of the field compute="_compute_name_custom", # Transform the fields in computed fields store=True, # If computed it will store the result select=True, # Force index on field readonly=True, # Field will be readonly in views inverse="_write_name" # On update trigger required=True, # Mandatory field translate=True, # Translation enable help='blabla', # Help tooltip text company_dependent=True, # Transform columns to ir.property search='_search_function' # Custom search function mainly used with compute ) # The string key is not mandatory # by default it wil use the property name Capitalized name = fields.Char() # Valid definition
One of the new features of the API is to be able to change only one attribute of the field:
name = fields.Char(string='New Value')
Boolean type field:
abool = fields.Boolean()
Store string with variable len.:
achar = fields.Char()
Specific options:
- size: data will be trimmed to specified size
- translate: field can be translated
Used to store long text.:
atext = fields.Text()
Specific options:
- translate: field can be translated
Used to store HTML, provides an HTML widget.:
anhtml = fields.HTML()
Specific options:
- translate: field can be translated
Store integer value. No NULL value support. If value is not set it returns 0:
anint = fields.Integer()
Store float value. No NULL value support. If value is not set it returns 0.0 If digits option is set it will use numeric type:
afloat = fields.Float() afloat = fields.Float(digits=(32, 32)) afloat = fields.Float(digits=lambda cr: (32, 32))
Specific options:
- digits: force use of numeric type on database. Parameter can be a tuple (int len, float len) or a callable that return a tuple and take a cursor as parameter
Store date. The field provides some helpers:
context_today
returns current day date string based on tztoday
returns current system date stringfrom_string
returns datetime.date() from stringto_string
returns date string from datetime.date
:
>>> from openerp import fields >>> adate = fields.Date() >>> fields.Date.today() '2014-06-15' >>> fields.Date.context_today(self) '2014-06-15' >>> fields.Date.context_today(self, timestamp=datetime.datetime.now()) '2014-06-15' >>> fields.Date.from_string(fields.Date.today()) datetime.datetime(2014, 6, 15, 19, 32, 17) >>> fields.Datetime.to_string(datetime.datetime.today()) '2014-06-15'
Store datetime. The field provide some helper:
context_timestamp
returns current day date string based on tznow
returns current system date stringfrom_string
returns datetime.date() from stringto_string
returns date string from datetime.date
:
>>> fields.Datetime.context_timestamp(self, timestamp=datetime.datetime.now()) datetime.datetime(2014, 6, 15, 21, 26, 1, 248354, tzinfo=<DstTzInfo 'Europe/Brussels' CEST+2:00:00 DST>) >>> fields.Datetime.now() '2014-06-15 19:26:13' >>> fields.Datetime.from_string(fields.Datetime.now()) datetime.datetime(2014, 6, 15, 19, 32, 17) >>> fields.Datetime.to_string(datetime.datetime.now()) '2014-06-15 19:26:13'
Store file encoded in base64 in bytea column:
abin = fields.Binary()
Store text in database but propose a selection widget. It induces no selection constraint in database. Selection must be set as a list of tuples or a callable that returns a list of tuples:
aselection = fields.Selection([('a', 'A')]) aselection = fields.Selection(selection=[('a', 'A')]) aselection = fields.Selection(selection='a_function_name')
Specific options:
- selection: a list of tuple or a callable name that take recordset as input
Store an arbitrary reference to a model and a row:
aref = fields.Reference([('model_name', 'String')]) aref = fields.Reference(selection=[('model_name', 'String')]) aref = fields.Reference(selection='a_function_name')
Specific options:
- selection: a list of tuple or a callable name that take recordset as input
Store a relation against a co-model:
arel_id = fields.Many2one('res.users') arel_id = fields.Many2one(comodel_name='res.users')
Specific options:
- comodel_name: name of the opposite model
Store a relation against many rows of co-model:
arel_ids = fields.One2many('res.users', 'rel_id') arel_ids = fields.One2many(comodel_name='res.users', inverse_name='rel_id')
Specific options:
- comodel_name: name of the opposite model
- inverse_name: relational column of the opposite model
Store a relation against many2many rows of co-model:
arel_ids = fields.Many2many('res.users') arel_ids = fields.Many2many(comodel_name='res.users', relation='table_name', column1='col_name', column2='other_col_name')
Specific options:
- comodel_name: name of the opposite model
- relation: relational table name
- columns1: relational table left column name
- columns2: relational table right column name
Note
fields and method name can conflict.
When you call a record as a dict it will force to look on the columns.
Default is now a keyword of a field:
You can attribute it a value or a function
name = fields.Char(default='A name') # or name = fields.Char(default=a_fun) #... def a_fun(self): return self.do_something()
Using a fun will force you to define function before fields definition.
There is no more direct creation of fields.function.
Instead you add a compute
kwarg. The value is the name of the function as a string or a function.
This allows to have fields definition atop of class:
class AModel(models.Model): _name = 'a_name' computed_total = fields.Float(compute='compute_total') def compute_total(self): ... self.computed_total = x
The function can be void. It should modify record property in order to be written to the cache:
self.name = new_value
Be aware that this assignation will trigger a write into the database. If you need to do bulk change or must be careful about performance, you should do classic call to write
To provide a search function on a non stored computed field
you have to add a search
kwarg on the field. The value is the name of the function
as a string or a reference to a previously defined method. The function takes the second
and third member of a domain tuple and returns a domain itself
def search_total(self, operator, operand): ... return domain # e.g. [('id', 'in', ids)]
The inverse key allows to trigger call of the decorated function when the field is written/"created"
To have one function that compute multiple values:
@api.multi @api.depends('field.relation', 'an_otherfield.relation') def _amount(self): for x in self: x.total = an_algo x.untaxed = an_algo
There is not anymore fields.related
fields.
Instead you just set the name argument related to your model:
participant_nick = fields.Char(string='Nick name', related='partner_id.name')
The type
kwarg is not needed anymore.
Setting the store
kwarg will automatically store the value in database.
With new API the value of the related field will be automatically
updated, sweet.
participant_nick = fields.Char(string='Nick name', store=True, related='partner_id.name')
Note
When updating any related field not all translations of related field are translated if field is stored!!
Chained related fields modification will trigger invalidation of the cache for all elements of the chain.
There is some use cases where value of the field must change depending of the current company.
To activate such behavior you can now use the company_dependent option.
A notable evolution in new API is that "property fields" are now searchable.
There is a dev running that will prevent to redefine copy by simply setting a copy option on fields:
copy=False # !! WIP to prevent redefine copy