How does one use the store parameter of function fields?
I've tried reading the docs, but it's a bit confusing.
Also, does store
work with any other field types?
To answer the second question first: The related
and sparse
fields are both subclasses of function
so store
may/should work with them, but I have not tried.
The idea behind the store
parameter is to tell OpenERP if it is okay to remember and save the results of calling the function in order to avoid calling it again.
For how it works, let's look at the following example:
'order_status': fields.function(
_order_status,
type='char',
method=True,
store= . . . ,
string='Order Status',
),
By default, store
is False
-- meaning that the function field will be evaluated everytime the record is requested.
There are, however, two other possible values -- True
, or a dict
of tuple
s.
store=True,
True
is easy to understand, and simply means that the value will be calculated once, stored, and then recalculated every time that record changes.
store={
'model.table': (function, ['field1', 'field2', ...], priority),
'another_model.table': (some_func, [], priority),
},
The dict
of tuple
s is both somewhat complicated as well as very powerful. With it we can tell OpenERP when we want the field recalculated.
The keys are tables, such as res.partner
or product.product
; the first item in the three item tuple is the function to call, the second items is a list of fields in the key table to monitor, and the last item is the priority, or sequence, to process the functions in if there are more than one1.
An example is in order:
store={
'product.product': (_get_product_dependent_ids, ['name','price'], 20),
'res.partner': (_get_partner_dependent_ids, ['login'], 10),
},
Working backwards, the priorities (last item of each tuple) tells us that the res.partner
tuple will run first, as it has a lower priority.
The middle item is the list of fields to monitor: for res.partner
OpenERP will monitor the login
field, and any time the login
field is changed OpenERP will call _get_partner_dependent_ids
; likewise, anytime the name
or price
fields for a product.product
record is changed, OpenERP will call _get_product_dependent_ids
2.
The first item in the tuple is the function to call, and it is the tricky part. The signature of this function is:
def _get_ids(key_table, cr, uid, ids_of_changed_records, context=None):
Note that key_table
is NOT self
! Even though this function is probably a method in your dependent class (for example, custom.table1
), the first parameter is not that table, but is the table listed as the key in the store dictionary -- product.product
or res.partner
in our example3.
What is this function supposed to do? It is supposed to return a list of all the record ids in your custom table that need to have that field recalculated.
Here's my function field:
'order_status': fields.function(
_order_status,
type='char',
method=True,
store={
'fnx.pd.order': (_get_schedule_ids_for_order, ['state'], 20),
},
and my store function:
def _get_schedule_ids_for_order(fnx_pd_order, cr, uid, ids, context=None):
if not isinstance(ids, (int, long)):
[ids] = ids
return [s.id for s in fnx_pd_order.browse(cr, uid, ids, context=context).schedule_ids]
What the field definition tells us is that any time the state
field is changed on a record in fnx.pd.order
, _get_schedule_ids_for_order
will be called with the ids of the records in fnx.pd.order
that had their state
field changed.
_get_schedule_ids_for_order
looks up the changed record, gets the ids of the linked schedule records, and returns them.
Footnotes:
The
priority
field sorts every_get_ids()
function for every field in the table, not just the_get_ids()
for an individual function. This is very useful when one function field depends on another.If the field list is empty, then any modification to any field will cause the function to be called.
-
If you need access to your own table inside the function you can do
self = key_table.pool.get('my_module_name_here.my_table_name_here')