This question has been flagged

As described here onchange methods are called with virtual recordset by Odoo, if a corresponding field is changed. Say I have the following onchange method:

@api.onchange('my_field')
def onchange_my_field(self):
pass

when Odoo calls this method internally, the "self" is a virtual recordset. However, I have a scenario where I would like to call this method manually, from the another object method, where I do NOT have virtual recordset, but a normal recordset instead, so if I call the onchange method like this:

self.onchange_my_field()

it gets called with ordinary recordset instead of virtual recordset (consequently the final result is as expected, except of huge difference in performance).


In order to avoid the performance penalty, I would like to get somehow virtual recordset from the ordinary "self" recordset I have for the moment and than call the onchange function using it. i.e. something like:

rec = get virtual recordset from self
rec.onchange_my_field()

it comes down to the question: How to get a virtual record/recordset from an ordinary record/recordset?

Avatar
Discard
Best Answer

Hi Temur

You could do it using the "new" method like this:

invoice_id = self.env['account.invoice'].new(vals)
invoice_id._onchange_partner_id()
invoice_vals = invoice_id._convert_to_write(invoice_id._cache)

Where vals is a normal dict of vals for the virtual record and invoice_vals will have the resulting virtual record modifications made by the onchange call. If you don't have the vals and you need to pass all the vals from a record you could use the method copy_data to get it by it's id like:

#from a recordset one record
vals = self.copy_data()
#from a record by id
vals = self.browse(id).copy_data()

also the copy_data method accept an optional dict argument with the default data for the result dict


UPDATE (Temur):

before calling "new" method,

if type(vals) == list:
vals = vals[0]

-see comment below.

Avatar
Discard
Author

Thanks Axel for your reply. I tried it and a code "vals = self.copy_data()" followed by "self.env['some.model'].new(vals)" gave me an error. I'll investigate the error deeper as soon as I'll have some spare time. I forgot to mention in my question that server used is a v9, should it work in v9 as well? Or you were referring to a different version?

That is the way of the new api, no matter what version you are using, v8, v9, v10 or master.

Author

It seems `new` method expects a dictionary, whereas `copy_data` method returns a list of dictionaries. I fixed the error by using `vals = self.copy_data()[0]` instead of `vals = self.copy_data()` and so I was able to get a virtual record.