Method Decorators In Odoo 8
Decorator simply decorates a method according to our needs. In odoo 7 we use cursor, uid, context and ids for defining all method here we can’t use such parameters, here we use self as the parameter when defining a method with certain method decorators.
This decorator's are passed the parameters explicitly to the method. Which provide a smooth way to write functions and avoid complications.
This manages the elements in two different API styles, namely:
- traditional styles.
- record styles.
In the “traditional” style, parameters like the db cursor, uid, context dictionary and record ids (usually written as cr, uid, context, ids) are passed explicitly to all methods.
In the “record” style, those parameters are hidden into model instances.
Recordsets is an Ordered collection of records of the same model, to replace browse_records, browse_list and browse_null.
Record is simply the database record which contains id, model, context, forces create, and we can write to database by this following way.
Example:
record = self
record.state = “State”
This will update the state in caches and call the write function to perform write action in database.
Decorators in odoo:
- @api.one
- @api.multi
- @api.model
- @api.depends
- @api.returns
- @api.onchange
- @api.constrains
- @api.noguess
@api.one
It is specific for one record and can not be used for multiple records. It automatically loop over record in the recordset. Self is redefined as current record.
Example
@api.one
def afun(self):
self.company_name = ‘Test’
self.company_code = ‘test123’
From this example, we will get an idea how will the function affects our records. This function will automatically writes company name and company code field of each records with ‘Test’ and ’test123’.
@api.multi
It can used for multiple record, so we can loop through it. Here Self contains recordset, so that we need a for loop for iterating through each record.
Example:
@api.multi
def afun(self):
self.company_name = ‘Test’
self.company_code = ‘test123’
If we are writing the function like this, we will get an error.
So rewrite the example :
@api.multi
def afun(self):
for record in self:
record.company_name = ‘Test’
record.company_code = ‘test123’
@api.model
This decorator will convert old API calls to decorated function to new API signature.
Example:
created_id = fields.Many2one('res.users', default=_default_created_user, string='Created by')
@api.model
def _default_created_user(self):
uid = self._uid
return uid
This will return the current user.
@api.depends
This decorator is specifically used for "fields.function" in odoo. The decorator function works only if any of the fields specified in the decorator is changed in the form.
Dependencies can be dotted paths when using sub-fields
For example:
@api.depends('partner_id.street')
def _get_street(self):
for record in self:
for line in record.partner_id:
record.street = line.street
If compute uses the values of other fields, it should be specified in depends().
-
compute is simply the fields.function in odoo 7, here the functional fields are replaced with compute, by assigning the function name to compute parameter, see the example given below
Computed field are not stored by default, they are computed the function and return the value, same as in odoo 7 here we use store = True to store the computed value to database.
Example
salary = fields.Float(compute='_get_salary', string='Salary', readonly=True)
@api.one
@api.depends('ta', 'da', 'hra', 'ba')
def _get_salary(self):
ta = (self.ta/100)*self.ba
da = (self.da/100)*self.ba
hra = (self.hra/100)*self.ba
self.salary = ta + da + hra + self.ba
From this example, we will get an idea how will the function affects database without store parameter. This function will not store calculated values without specifying the parameter store as True
@api.returns
This decorator is used for decorating the returned value from a method. It guarantees the unity of returned value from a method. It will return a RecordSet of specified model. If an old API function calls a new API function it will automatically convert it into a list of ids.
Example:
@api.returns('self')
def _get_return(self):
return self
@api.onchange
In odoo 7 we use onchange method, in which an onchange attribute is written in the corresponding field tag in xml and in py file, here we use a decorator. Which will avoid the onchange attribute in xml file. The working of this decorator is same as the working of onchange method in odoo 7, the fields are written as the parameter of the function.
Example
@api.onchange('date_of_birth','age')
def onchange_age_calculation(self ):
if not self.date_of_birth:
self.age = 0
else:
today_date = datetime.now().year
date_split = self.date_of_birth.split('-',1)
birth_year = date_split[0]
self.age = today_date -int(birth_year)
From this example , we will get an idea how will the function affects our records. This function will automatically writes age field when changing the value of date_of_birth field in form view.
1.Onchange with Warning
Example:
@api.onchange('date_of_birth','age')
def onchange_age_calculation(self ):
birth_date = self.date_of_birth
now_date = str(datetime.now().date())
if birth_date == now_date:
return {
'warning': {
'title': _('Warning!'),
'message': _('You are not a valid user.'),
},
'value': {
'date_of_birth': 1
}
}
2. Onchange with Domain
Example:
@api.onchange('partner_id')
def _onchange_partner_id(self):
contact_ids = self.env['res.partner'].search([('parent_id','=',self.partner_id.id), ('type','=','site_address')])
if contact_ids:
self.site_id = contact_ids[0]
else:
self.site_id = self.partner_id.id
return {'domain': {'site_id': [('parent_id', '=', self.partner_id.id )]}}
@api.constrains
This decorator will ensure that decorated function will be called on create, write, unlink operation. It will act as a constraint checker. This will especially used for warning messages and validation.
Example:
1. Warning with appropriate message.
@api.one
@api.constrains('roll_number')
def _check_roll_number(self):
if self.roll_number and type(self.roll_number) != int’:
raise Warning(_('Roll number must be numeric.'))
2. Validation with appropriate message.
@api.one
@api.constrains(‘password’, 'confim_password’)
def _check_password(self):
if self.password == self.confim_password:
raise ValidationError("Fields Password and Confirm password must be same")
@api.noguess
This decorator prevent new API decorators to alter the output of a method.
From this we get an idea about the decorator and how to use, where to use. I hope that this will be helpful to write methods using decorator in odoo 8.
Thank you.
Pls Mention Diff b/w
Pls Mention Diff b/w @api.depends and @api.onchange....
@api.depends is used for
@api.depends is used for functional fields, where the function calculate the value and store it. If the function use any other field value for calculation then we can write that field in @api.depend decorator. i.e, the fuction calculation depends up on other field value. For example, in salary calculation function we use HRA, TA, DA etc,. So here we use a functional field for salary calculation and we know that the calculation depends on HRA, TA, DA etc, so we write that fields in @api.depends decorator.
In odoo 7 we used onchange attribute in xml, that will replaced by the @api.onchange decorator in odoo8. Here we just write the decorator with field and the functionality is written below the decorator. If the field value changes in form view then the function is called.
I don't understand, if
I don't understand, if @api.one is specific for one record (can not be used for multiple records) why does it loop over the records in the recordset? over what does it loop?
if api.one is used then the
if api.one is used then the functionality will be reflected for all records, but in case of multi its specific to one record.
Good blog.. It will be great
Good blog.. It will be great if you could explain more about api.model and also how can we pass domain and warning to a onchange method using this new api.onchange decorator?
Thankyou. We appreciate your
Thankyou. We appreciate your suggestions and have made those updates in the blog. If you have any other helpful ideas, let me know.