6

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?

forvas
  • 9,801
  • 7
  • 62
  • 158

1 Answers1

11

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
CZoellner
  • 13,553
  • 3
  • 25
  • 38
  • Thank you very much @CZoellner, I was looking for something like your solution. – forvas May 25 '18 at 07:58
  • so helpful but how can i send data in this action i want to send self.partner_id to partner_id in this action ```action = self.env.ref('sale_crm.sale_action_quotations_new').read()[0]``` thanks – omar ahmed Jun 19 '20 at 12:49
  • I don't understand you fully, maybe open a question with more details? – CZoellner Jun 19 '20 at 13:03
  • i use this action in function in crm opportunity so i need to send data in this action like opportunity customer (partner_id) like in context ```action = self.env.ref('sale_crm.sale_action_quotations_new').read()[0]``` – omar ahmed Jun 20 '20 at 10:43