背景:同一个模块,两组开发人员对同一个模型的form视图进行了二开。在没有指定外部ID的情况下,odoo是如何选择展示展示哪个视图呢?

上干货

  1. 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
  1. 上面的核心在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)
···
  1. 检查权限通过后,调用_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
  1. 此处我们讨论的是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
  1. 是不是很惊喜,毛都没有,看不出来如何做的选择。别着急,看ir.ui.view的模型吧。

有点坑啊,大家在视图继承的时候。权重基本上是默认的,也就是说若不考虑name的影响,那么默认视图将永远是最先添加的基础视图。但是,这里name的排序居然还在ID的前面,这就有的玩了嘛,起名字也是门艺术了。

  1. 好了回归正题,在步骤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'))

结束

【odoo】【知识点】视图的继承逻辑的更多相关文章

  1. 关于类视图选择继承APIView还是工具视图(ListAPIView、CreateAPIView等等)

    APIView使用方法,直接继承APIView,get或者post请求.方法很简单1.先获取到要操作的数据,然后把数据放到serializer中序列化或者反序列化,最后return返回值(记得.dat ...

  2. ODOO里视图开发案例---定义一个像tree、form一样的视图

    odoo里视图模型MVC模式: 例子:在原来的视图上修改他: var CustomRenderer = KanbanRenderer.extend({ ....});var CustomRendere ...

  3. Odoo中的模型继承、视图继承、Qweb模板继承详解

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826114.html 在实际开发过程中,经常会遇到需要修改Odoo原生逻辑的情况.然而,直接修改Odoo底 ...

  4. 第八章 Odoo 12开发之业务逻辑 - 业务流程的支持

    在前面的文章中,我们学习了模型层.如何创建应用数据结构以及如何使用 ORM API 来存储查看数据.本文中我们将利用前面所学的模型和记录集知识实现应用中常用的业务逻辑模式. 本文的主要内容有: 以文件 ...

  5. 解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑

    之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该IVi ...

  6. Odoo form视图详解

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826350.html 一:Header头部 header区域一般用于展示文档流转的阶段和生命周期,以及动作 ...

  7. 自定义视图(继承View)

    前言 Android提供了丰富的控件,但是有时候还是不能满足自己的需求,这时候就需要自定义视图了,自定义视图分为几种,一种为继承为View的,一种为继承于ViewGroup的.继承于View的需要我们 ...

  8. 自定义控件(视图)2期笔记09:自定义视图之继承自ViewGroup(仿ViewPager效果案例)

    1. 这里我们继承已有ViewGroup实现自定义控件,模拟出来ViewPager的效果,如下: (1)实现的效果图如下: (2)实现步骤: • 自定义view继承viewGroup • 重写onLa ...

  9. 12.Yii2.0框架视图模版继承与模版相互调用

    目录 模板渲染的两种方式 加载视图 index.php 和 about.php 页面 建立控制器HomeController php 新建模板 home\index.php 新建模板home\abou ...

随机推荐

  1. 16. Vue2.4+新增属性$attrs

    vm.$attrs简介 首先我们来看下vue官方对vm.$attrs的介绍: 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外).当一个组件没有声明 ...

  2. JAVAEE_Servlet_17_关于乱码问题

    关于乱码问题 * 数据传递过程中的乱码 解释:数据传递过程中的乱码是指: 将数据从浏览器发送给服务器的时候,服务器接收到的数据是乱码的. - ISO-8859-1 是国际标准码,不支持中文编码,它兼容 ...

  3. 各种平衡树收集(收集控(‐^▽^‐))\平衡树模板题的各种花式做法QAQ

    非旋转treap!!!(FHQ Treap) 递归版Splay(无需维护父指针) Scapegoat _ Tree--替罪羊树(一只(棵)特立独行的猪(树)) 宗法树(平衡线段树\finger_tre ...

  4. 听说你买的基金又“绿了”,手把手教你用 Python选出好基金

    打工人打工魂打工都是人上人,红基金绿基金绿了又绿你基金.今天教大家一招不再被(基金)绿. 01 开发环境 Windows10 Python3 Pycharm 一些必要的库 02 步骤 1. 获取基金排 ...

  5. 在 Y 分钟内学会 Python

    在 Y 分钟内学会 Python 这是翻译, 原文地址: Learn Python in Y Minutes 在 90 年代初, Python 由 Guido van Rossum 创造, 现在, 它 ...

  6. 1.1.08- Python变量的关联,绑定,引用

    Python中关联.绑定,引用的含义: 在Python中,变量没有类型 关联/绑定/引用都是指变量和一个对象的关联关系. 在交互模式下查看变量的绑定关系: >>>help(" ...

  7. 【SpringBoot】Springboot1.5.9整合WebSocket

    一.WebSocket介绍 1.WebSocket是什么? WebSocket是协议,是HTML5开始提供的基于TCP(传输层)的一种新的网络协议, 它实现了浏览器与服务器全双工(full-duple ...

  8. JAVA的安装

    1.从JAVA官网 下载 注意选择自己需要的版本 2.百度云盘 链接:https://pan.baidu.com/s/1deOFGN1xB0mgz6s2mTRXdA 提取码:ke97 安装JAVA J ...

  9. 获取InputStream对象的方法

    获取InputStream对象的方法 getResourceAsStream(String path) 默认path路径位于Class所在Module的src目录下 . InputStream is ...

  10. mysql-.frm,.myd,myi备份如何导入mysql

    .frm..myd..myi文件,也就是说是MySQL的原始数据文件,这三个文件分别是: .frm 表结构文件 .myd 表数据文件 .myi 表索引文件 方法,如下: 新建一个数据库 在my.ini ...