摘要
同一实体模型的form主视图二开,odoo会先启用models.py中的load_views函数,决定展现哪一个视图。
正文
【odoo】【知识要点】主视图的承继逻辑性
情况:同一个控制模块,2组开发者对同一个实体模型的form主视图开展了二开。在沒有特定外界ID的状况下,odoo是如何选择展现展现哪一个主视图呢?
上干货知识
- odoo在载入主视图的情况下,最先启用的models.py中的
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
- 上边的关键在
fields_view_get
涵数,以下,提取关键的內容
@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
self.check_access_rights('read')
view = self.env['ir.ui.view'].sudo().browse(view_id)
# 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)
···
- 查验管理权限根据后,启用
_fields_view_get
涵数,若客户启用的主视图沒有特定主视图ID,那麼将启用默认设置的主视图
@api.model
def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
View = self.env['ir.ui.view'].sudo()
result = {
'model': self._name,
'field_parent': False,
}
# try to find a view_id if none provided
if not view_id:
# <view_type>_view_ref in context can be used to overrride the default view
view_ref_key = view_type '_view_ref'
view_ref = self._context.get(view_ref_key)
if view_ref:
if '.' in view_ref:
module, view_ref = view_ref.split('.', 1)
query = "SELECT res_id FROM ir_model_data WHERE model='ir.ui.view' AND module=%s AND name=%s"
self._cr.execute(query, (module, view_ref))
view_ref_res = self._cr.fetchone()
if view_ref_res:
view_id = view_ref_res[0]
else:
_logger.warning('%r requires a fully-qualified external id (got: %r for model %s). '
'Please use the complete `module.view_id` form instead.', view_ref_key, view_ref,
self._name)
if not view_id:
# otherwise try to find the lowest priority matching ir.ui.view
view_id = View.default_view(self._name, view_type)
if view_id:
# read the view with inherited views applied
root_view = View.browse(view_id).read_combined(['id', 'name', 'field_parent', 'type', 'model', 'arch'])
result['arch'] = root_view['arch']
result['name'] = root_view['name']
result['type'] = root_view['type']
result['view_id'] = root_view['id']
result['field_parent'] = root_view['field_parent']
result['base_model'] = root_view['model']
else:
# fallback on default views methods if no ir.ui.view could be found
try:
arch_etree = getattr(self, '_get_default_%s_view' % view_type)()
result['arch'] = etree.tostring(arch_etree, encoding='unicode')
result['type'] = view_type
result['name'] = 'default'
except AttributeError:
raise UserError(_("No default view of type '%s' could be found !", view_type))
return result
- 这里大家探讨的是odoo是怎样取默认设置主视图的,再进ir.ui.view实体模型的
default_view
涵数查询
@api.model
def default_view(self, model, view_type):
""" Fetches the default view for the provided (model, view_type) pair:
primary view with the lowest priority.
:param str model:
:param int view_type:
:return: id of the default view of False if none found
:rtype: int
"""
domain = [('model', '=', model), ('type', '=', view_type), ('mode', '=', 'primary')]
return self.search(domain, limit=1).id
- 是否很意外惊喜,毛也没有,看不出怎样做的挑选。不要着急,看ir.ui.view的模型吧。
有点儿坑啊,大伙儿在主视图承继的情况下。权重值大部分是默认设置的,换句话说若不考虑到name的危害,那麼默认设置主视图将始终是最开始加上的基本主视图。可是,这儿name的排列竟然仍在ID的前边,这就会有的玩了嘛,取名字也是门造型艺术了。
- 好啦重归主题,在流程3中,取得了默认设置主视图后,大家得到的主视图有可能是承继主视图,也是有可能是基本主视图。那麼将根据
read_combined
涵数拼凑出去以基本主视图为架构,包括全部承继主视图內容的etree目标。
def read_combined(self, fields=None):
"""
Utility function to get a view combined with its inherited views.
* Gets the top of the view tree if a sub-view is requested
* Applies all inherited archs on the root view
* Returns the view with all requested fields
.. note:: ``arch`` is always added to the fields list even if not
requested (similar to ``id``)
"""
# introduce check_view_ids in context
if 'check_view_ids' not in self._context:
self = self.with_context(check_view_ids=[])
check_view_ids = self._context['check_view_ids']
# if view_id is not a root view, climb back to the top.
root = self
while root.mode != 'primary':
# Add inherited views to the list of loading forced views
# Otherwise, inherited views could not find elements created in their direct parents if that parent is defined in the same module
check_view_ids.append(root.id)
root = root.inherit_id
# arch and model fields are always returned
if fields:
fields = list({'arch', 'model'}.union(fields))
# read the view arch
[view_data] = root.read(fields=fields)
view_arch = etree.fromstring(view_data['arch'].encode('utf-8'))
if not root.inherit_id:
if self._context.get('inherit_branding'):
view_arch.attrib.update({
'data-oe-model': 'ir.ui.view',
'data-oe-id': str(root.id),
'data-oe-field': 'arch',
})
arch_tree = view_arch
else:
if self._context.get('inherit_branding'):
root.inherit_branding(view_arch)
parent_view = root.inherit_id.read_combined(fields=fields)
arch_tree = etree.fromstring(parent_view['arch'])
arch_tree = self.browse(parent_view['id']).apply_inheritance_specs(arch_tree, view_arch)
# and apply inheritance
arch = root.apply_view_inheritance(arch_tree, self.model)
return dict(view_data, arch=etree.tostring(arch, encoding='unicode'))
完毕
关注不迷路
扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!
温馨提示:如果您访问和下载本站资源,表示您已同意只将下载文件用于研究、学习而非其他用途。
评论0