Search code examples
odooopenerp-7

What do I return for function field value?


I have a function field, but I don't know what should the function return.

Here's my code:

the function:

def _property_expense_preset_expenses(self, cr, uid, ids, expenses, arg, context):
    spus = self.browse(cr, uid, ids)
    _spu = False
    for spu in spus:
    _spu = spu

    if(_spu):
        expenses_acc = {}
        property_expense_presets = _spu.property_expense_presets
        for property_expense_preset in property_expense_presets:
            expenses = property_expense_preset.expense_preset.expenses
            for expense in expenses:
            expenses_acc[expense.id] = expense
        return expenses_acc
    else:
        return {}

The field definition:

'expenses'      : fields.function(
                _property_expense_preset_expenses,
                type='one2many',
                obj="property.expense",
                method=True,
                string='Expenses'
            ),

The code above doesn't work, it raises an error : KeyError: 788


Solution

  • Like all function fields, it must return a dictionary with an entry and value for every ID you get passed in ids, although your value can be False, None, []

    In your case your functional field is declared as a one2many type which means your functional field must return a dictionary with an entry per id and the value, a list of integers that represent the ids of the related table, in your case, property.expense.

    A very common pattern is:

    def _property_expense_preset_expenses(self, cr, uid, ids, field, arg, context = None):
        res = {}
        for spu in self.browse(cr, uid, ids, context = context):
            res[spu.id] = []
            for preset in spu.property_expense_presets:
                res[spu.id].extend([x.id for x in preset.expense_preset.expenses])
    
        return res
    

    Assuming ids contains 1,2,3 you will get a result of {1: [...], 2: [...], 3: []}

    Where each list contains the integer ids of the expenses or an empty list if there are none.

    As a general comment, I note your code doesn't default the context argument to None or pass the context as a named argument to the browse method - it is important to do both.