How does one use the store parameter of function fields?

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

        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 tuples 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_ids2.

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:

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

  2. If the field list is empty, then any modification to any field will cause the function to be called.

  3. 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')
    

Leave a Comment