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:

  1. traditional styles.
  2. 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:

  1. @api.one
  2. @api.multi
  3. @api.model
  4. @api.depends
  5. @api.returns
  6. @api.onchange
  7. @api.constrains
  8. @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().

  1. 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.

Comments

Rajasree R: @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. ".

Leave a Reply

Your email address will not be published. Required fields are marked *

  1. Anonymous says:

    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?

    1. Rajasree R says:

      Thankyou. We appreciate your suggestions and have made those updates in the blog. If you have any other helpful ideas, let me know.

  2. SFC says:

    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?

    1. Rajasree R says:

       if api.one is used then the functionality will be reflected for all records, but in case of multi its specific to one record.

  3. Hasi says:

    Pls Mention Diff b/w @api.depends and @api.onchange….

    1. Rajasree R says:

      @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.

© 2020 Zesty Beanz Pvt Ltd All Rights Reserved.