动作的加载:
刷新视图页面执行load_views方法
/web/dataset/call_kw/model_name/load_views
在odoo/models.py的BaseModel中有一个load_views方法
@api.model def load_views(self, views, options=None): """ Returns the fields_views of given views, along with the fields of the current model, and optionally its filters for the given action. :param views: list of [view_id, view_type] :param options['toolbar']: True to include contextual actions when loading fields_views :param options['load_filters']: True to return the model's filters :param options['action_id']: id of the action to get the filters :return: dictionary with fields_views, fields and optionally filters """ options = options or {} result = {} toolbar = options.get('toolbar') result['fields_views'] = { v_type: self.fields_view_get(v_id, v_type if v_type != 'list' else 'tree', toolbar=toolbar if v_type != 'search' else False) for [v_id, v_type] in views } result['fields'] = self.fields_get() if options.get('load_filters'): result['filters'] = self.env['ir.filters'].get_filters(self._name, options.get('action_id')) return result
odoo/models.py
@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
""" fields_view_get([view_id | view_type='form'])
Get the detailed composition of the requested view like fields, model, view architecture
:param view_id: id of the view or None
:param view_type: type of the view to return if view_id is None ('form', 'tree', ...)
:param toolbar: true to include contextual actions
:param submenu: deprecated
:return: dictionary describing the composition of the requested view (including inherited views and extensions)
:raise AttributeError:
* if the inherited view has unknown position to work with other than 'before', 'after', 'inside', 'replace'
* if some tag other than 'position' is found in parent view
:raise Invalid ArchitectureError: if there is view type other than form, tree, calendar, search etc defined on the structure
"""
View = self.env['ir.ui.view']
# Get the view arch and all other attributes describing the composition of the view
result = self._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
# Override context for postprocessing
if view_id and result.get('base_model', self._name) != self._name:
View = View.with_context(base_model_name=result['base_model'])
# Apply post processing, groups and modifiers etc...
xarch, xfields = View.postprocess_and_fields(self._name, etree.fromstring(result['arch']), view_id)
result['arch'] = xarch
result['fields'] = xfields
# Add related action information if aksed
if toolbar:
bindings = self.env['ir.actions.actions'].get_bindings(self._name)
resreport = [action
for action in bindings['report']
if view_type == 'tree' or not action.get('multi')]
resaction = [action
for action in bindings['action']
if view_type == 'tree' or not action.get('multi')]
resrelate = []
if view_type == 'form':
resrelate = bindings['action_form_only']
for res in itertools.chain(resreport, resaction):
res['string'] = res['name']
result['toolbar'] = {
'print': resreport,
'action': resaction,
'relate': resrelate,
}
return result
addons/base/models/ir_actions.py
@api.model
@tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'model_name')
def get_bindings(self, model_name):
""" Retrieve the list of actions bound to the given model.
:return: a dict mapping binding types to a list of dict describing
actions, where the latter is given by calling the method
``read`` on the action record.
"""
cr = self.env.cr
query = """ SELECT a.id, a.type, a.binding_type
FROM ir_actions a, ir_model m
WHERE a.binding_model_id=m.id AND m.model=%s
ORDER BY a.id """
cr.execute(query, [model_name])
# discard unauthorized actions, and read action definitions
result = defaultdict(list)
user_groups = self.env.user.groups_id
for action_id, action_model, binding_type in cr.fetchall():
try:
action = self.env[action_model].browse(action_id)
action_groups = getattr(action, 'groups_id', ())
if action_groups and not action_groups & user_groups:
# the user may not perform this action
continue
result[binding_type].append(action.read()[0])
except (AccessError, MissingError):
continue
return result
能否通过修改ir.actions.server的表结构,增加binding_view_id字段,动作定义时设置binding_view_id字段,实现相同模型不同视图显示不通的动作内容,感觉是可以的,需要验证。
动作的执行:
addons/web/controllers/main.py
@http.route('/web/action/run', type='json', auth="user") def run(self, action_id): result = request.env['ir.actions.server'].browse([action_id]).run() return clean_action(result) if result else False
addons/base/models/ir_actions.py
@api.multi def run(self): """ Runs the server action. For each server action, the run_action_<STATE> method is called. This allows easy overriding of the server actions. :param dict context: context should contain following keys - active_id: id of the current object (single mode) - active_model: current model that should equal the action's model The following keys are optional: - active_ids: ids of the current records (mass mode). If active_ids and active_id are present, active_ids is given precedence. :return: an action_id to be executed, or False is finished correctly without return action """ res = False for action in self: eval_context = self._get_eval_context(action) if hasattr(self, 'run_action_%s_multi' % action.state): # call the multi method run_self = self.with_context(eval_context['env'].context) func = getattr(run_self, 'run_action_%s_multi' % action.state) res = func(action, eval_context=eval_context) elif hasattr(self, 'run_action_%s' % action.state): active_id = self._context.get('active_id') if not active_id and self._context.get('onchange_self'): active_id = self._context['onchange_self']._origin.id if not active_id: # onchange on new record func = getattr(self, 'run_action_%s' % action.state) res = func(action, eval_context=eval_context) active_ids = self._context.get('active_ids', [active_id] if active_id else []) for active_id in active_ids: # run context dedicated to a particular active_id run_self = self.with_context(active_ids=[active_id], active_id=active_id) eval_context["env"].context = run_self._context # call the single method related to the action: run_action_<STATE> func = getattr(run_self, 'run_action_%s' % action.state) res = func(action, eval_context=eval_context) return res