10

I have a computed field in Odoo with a function. Everything works fine when I don't add the store argument. When I add the store argument, it doesn't execute the code at all.

My code:

class opc_actuelewaardentags(models.Model):
    _name = 'opc_actuelewaardentags'

    unit = fields.Char(compute='changeunit')

    def changeunit(self):
        print "print"
        allrecords_actwaardent = self.search([])

        obj_taginst = self.env['opc_taginstellingen']
        allrecords_taginst = obj_taginst.search([])


        for i in allrecords_actwaardent:
            for j in allrecords_taginst:
                if i.tagnaam == j.tagnaam and i.unit != j.unit:
                    i.unit = j.unit

So: when I call the code like this:

unit = fields.Char(compute='changeunit')

The code is executed (shows "print").

When I call the code like this:

unit = fields.Char(compute='changeunit', store=True)

The code is not executed (doesn't show "print").

Is there anything wrong in my code? Or is this a bug? It seems so strange to me...

I need to be able to store the values in the database so I can filter on unit in the tree view.

edit: I applied Juan Salcedo's tip. Didn't work...

This is how I did it:

unit = fields.Char(default = changeunit)    

def changeunit(self):
    print "print"
    allrecords_actwaardent = self.search([])

    obj_taginst = self.env['opc_taginstellingen']
    #Hier dan i.p.v. self werken met dat obj_taginst
    allrecords_taginst = obj_taginst.search([])


for i in allrecords_actwaardent:
    for j in allrecords_taginst:
        if i.tagnaam == j.tagnaam and i.unit != j.unit:
            i.unit = j.unit
return i.unit

Gives error:

NameError: name 'changeunit' is not defined

I also tried putting the unit field below def changeunit(self), but didn't work either.

RobbeM
  • 727
  • 7
  • 16
  • 36

5 Answers5

4

Store=True without @api.depends means it will execute only once while the column/field is going to be created.

so the effect you want to fire that method everytime will not be achieve with store=True without @api.depends or you need to remove store=True then it will calculate everytime when you access this field.

This are the changes you required to update in your code but before that you need to remove that column from database and after that restart server and upgrade module then it will come to there.

class opc_actuelewaardentags(models.Model):
    _name = 'opc_actuelewaardentags'

    unit = fields.Char(compute='changeunit')

    @api.multi
    def changeunit(self):
      print "print"  
        for obj in self:
            allrecords_actwaardent = self.search([])
            obj_taginst = self.env['opc_taginstellingen']
            allrecords_taginst = obj_taginst.search([])
            for i in allrecords_actwaardent:
                for j in allrecords_taginst:
                    if i.tagnaam == j.tagnaam and i.unit != j.unit:
                       obj.unit = j.unit
                       break

Another way: store = False never stored any value in database so if you want to store that value in database and don't won't to be updated (means it's fixed when create or update record) then you just need to override create/write method and inside update this field's value.

@api.model
def create(self, vals):
    vals.update({'field':value})
    return super(class_name,self).create(vals)
  • Thank you, the first code was executed now. (Had to change obj.unit into i.unit though) But now there are still problems. Problem 1: The values are still not stored into the database. No column unit is created. Problem 2: It takes a lot of time to load the view (was faster before). Problem 3: I still cannot filter on unit in the tree view. – RobbeM Aug 12 '15 at 06:33
  • if your field is created once then it will never executed your compute method again, even after you upgrade module that's why I told you to remove that field from database, so your filed is going to be create and your method will execute, I can not help you more in your method coding because I don't what you want to do with that code so. Just check that method is called and update your accordingly. – Emipro Technologies Pvt. Ltd. Aug 12 '15 at 06:41
  • I did "alter table opc_actuelewaardentags drop column unit" before changing the code, restarting the server and upgrading the module... – RobbeM Aug 12 '15 at 07:18
3

When we set store=True then we need to specify when we need to compute that function. Using @api.depends('fields') in that you specify field name when the change the value of the fields then compute method is call.

name = fields.Char('name')
length = fields.Integer(compute='get_length','Length',store=True)

@api.depends('name')
def get_length(self):
    self.length=len(name)

In this example when you change the name then get_length function is call.

Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99
1

This is not an issue, because Store = True (by the way it's recommended) tells odoo that when you compute the field store it's value to the database, so when you call this record next time the framework will retrieve the value from the database, and this value will be recomputed when any of the fields in the depends annotation is updated in the database or the UI.

so the code is not warking because when you specify the store = True after creating the value the value will be False and odoo will not recompute it until you change one of the fields that trigger the function.

you need to compute this field manually with a query to set the value for the existing records that you have in the database, don't worry about the new records odoo will compute and store the values.

so store = True. means compute and store the value in the database and don't compute it again until one of the field is edited you need to compute the value for the existing records manually for the first time.

Charif DZ
  • 14,415
  • 3
  • 21
  • 40
0

Here's a solution that might work for you, it's not perfect because it will could call the method often yet without real need most of the time.

First add a new field that is computed.. Add that field to the UI where you need it and also hide it. It's not necessary to show it. You have to have it in the ui to force odoo to compute it.

When you compute the value of the field, also change the value of the field you really wanted to edit. Since a compute method can update multiple fields, it will work.

You don't have to make the original field as computed as far as I can say...

But since you're modifying some fields using sql which isn't really good as you admitted yourself... Why don't you change that field with SQL at the same time? Make it easier on the Odoo side without hacks and make sure that your method that changes SQL kind of changes everything as it should. It's like you're editing one half of the problem and expecting odoo to catch data changes on itself. In order to achieve that, you'd need to have some way to have the database notify odoo that something changed... unfortunately, Postgresql doesn't do that so make sure that while you're updating something from SQL, that you have consistent data after doing your changes.

Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99
0

i noticed this issue too, but in my case it was not necessary to store it in the database. so i kept it as store=false and the computed field worked and it has a value in the view and that's what mattered, only to have the values in the view..

so when you set store=true, only new records will have a value in the computed field, while old data won't have values in the computed field

therefore you have to reset the values of the fields used in the computation of the field(depend fields)

by writing a write statement inside the compute function, to reassign these fields their own values again, as if they are just created

for record in self.env['class'].search([]):
    record.field= record.field

record.field ->>> the fields used in field computation or api.depends(fields)

fatema
  • 1