pythonxmlodooodoo-10

How to return an existing ir.actions.act_window from Python in Odoo 10?


What I need

If the user clicks on my button, take him to different views of different models depending on a field of the current record.

What I did

I have declared a type object button to call a Python method. Inside it, I check the field. If its value is A, I redirect him to the model X and if its value is B, I redirect him to the model Y.

The code

@api.multi
def my_button_method(self):
    self.ensure_one()
    if self.my_field == 'A':
        action_id = self.env.ref(
            'my_module.my_ir_actions_act_window_A')
        return action_id.__dict__
    elif self.my_field == 'B':
        action_id = self.env.ref(
            'my_module.my_ir_actions_act_window_B')
    else:
        action_id = False
    if action_id:
        return action_id.__dict__

If I write this after the definition of action_id:

_logger.info(action_id.name)
_logger.info(action_id.type)
_logger.info(action_id.res_model)
_logger.info(action_id.view_type)
_logger.info(action_id.view_mode)
_logger.info(action_id.search_view_id)
_logger.info(action_id.help)

I get the right values. So, after googling I saw that __dict__ gives you a dictionary whose keys are the attributes of the object and whose values the values of those attributes.

But the code is giving an error because action_id.__dict__ doesn't return a dictionary with the expected attributes of the action and its values, but the following instead:

{
    '_prefetch': defaultdict(
        <type 'set'>,
        {
            'ir.actions.act_window': set([449])
        }
    ),
    'env': <odoo.api.Environment object at 0x7f0aa7ed7cd0>,
    '_ids': (449,)
}

Can anyone tell me why? I'm trying to avoid this code:

@api.multi
def my_button_method(self):
    self.ensure_one()
    if self.my_field == 'A':
        action_id = self.env.ref(
            'my_module.my_ir_actions_act_window_A')
    elif self.my_field == 'B':
        action_id = self.env.ref(
            'my_module.my_ir_actions_act_window_B')
    else:
        action_id
    if action_id:
        return {
            'name': action_id.name,
            'type': action_id.type,
            'res_model': action_id.res_model,
            'view_type': action_id.view_type,
            'view_mode': action_id.view_mode,
            'search_view_id': action_id.search_view_id,
            'help': action_id.help,
        }

May be there is a much better solution using a server action, if so, does anyone know how?


Solution

  • You can do the really short "style":

    action = self.env.ref("my_module.my_ir_actions_act_window_A").read()[0]
    return action
    

    You will find a lot of examples this "style" around in Odoo code.

    Edit: that should also work in Odoo 7-14

    Edit: for newer versions for example Odoo 15+ you can also use the following:

    action = self.env["ir.actions.actions"]._for_xml_id(
        "my_module.my_ir_actions_act_window_A"
    )
    return action