odoo17核心概念view5——ir_ui_view.py

2023-12-26 10:15
文章标签 ui 概念 py 核心 view ir odoo17 view5

本文主要是介绍odoo17核心概念view5——ir_ui_view.py,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这是view系列的第5篇文章,介绍一下view对应的后端文件ir_ui_view.py,它是base模块下的一个文件
位置:odoo\addons\base\models\ir_ui_view.py

该文件一共定义了三个模型

1.1 ir.ui.view.custom

查询数据库这个表是空的,从名字看和数据库表结构看, 这个表应该是view和user的三方表,可以根据用户自定义view, 但是案例呢?

class ViewCustom(models.Model):_name = 'ir.ui.view.custom'_description = 'Custom View'_order = 'create_date desc'  # search(limit=1) should return the last customization_rec_name = 'user_id'ref_id = fields.Many2one('ir.ui.view', string='Original View', index=True, required=True, ondelete='cascade')user_id = fields.Many2one('res.users', string='User', index=True, required=True, ondelete='cascade')arch = fields.Text(string='View Architecture', required=True)def _auto_init(self):res = super(ViewCustom, self)._auto_init()tools.create_index(self._cr, 'ir_ui_view_custom_user_id_ref_id',self._table, ['user_id', 'ref_id'])return res

1.2 ir.ui.view

截取一部分字段, view的字典表,保存从xml中解析的view信息。


class View(models.Model):_name = 'ir.ui.view'_description = 'View'_order = "priority,name,id"name = fields.Char(string='View Name', required=True)model = fields.Char(index=True)key = fields.Char(index='btree_not_null')priority = fields.Integer(string='Sequence', default=16, required=True)type = fields.Selection([('tree', 'Tree'),('form', 'Form'),('graph', 'Graph'),('pivot', 'Pivot'),('calendar', 'Calendar'),('gantt', 'Gantt'),('kanban', 'Kanban'),('search', 'Search'),('qweb', 'QWeb')], string='View Type')arch = fields.Text(compute='_compute_arch', inverse='_inverse_arch', string='View Architecture',help="""This field should be used when accessing view arch. It will use translation.Note that it will read `arch_db` or `arch_fs` if in dev-xml mode.""")arch_base = fields.Text(compute='_compute_arch_base', inverse='_inverse_arch_base', string='Base View Architecture',help="This field is the same as `arch` field without translations")arch_db = fields.Text(string='Arch Blob', translate=xml_translate,help="This field stores the view arch.")arch_fs = fields.Char(string='Arch Filename', help="""File from where the view originates.Useful to (hard) reset broken views or to read arch from file in dev-xml mode.""")

1.3 Model

这是一个抽象模型,

class Model(models.AbstractModel):_inherit = 'base'_date_name = 'date'         #: field to use for default calendar view

它继承自base模型,让我们看看base模型是何方神圣,从注释看,这是一个基本模型,所有的模型都要继承它。
odoo\addons\base\models\ir_model.py
这是一个抽象模型,抽象的只有一名字而已。估计又很多地方对这个模型进行了扩展。我们搜索一下

#
# IMPORTANT: this must be the first model declared in the module
#
class Base(models.AbstractModel):""" The base model, which is implicitly inherited by all models. """_name = 'base'_description = 'Base'

在这里插入图片描述
前端的viewService中通过orm调用的getViews就是最终就是调用了这个模型的get_views方法

    @api.modeldef get_views(self, views, options=None):""" Returns the fields_views of given views, along with the fields ofthe current model, and optionally its filters for the given action.The return of the method can only depend on the requested view types,access rights (views or other records), view access rules, options,context lang and TYPE_view_ref (other context values cannot be used).Python expressions contained in views or representing domains (onpython fields) will be evaluated by the client with all the contextvalues as well as the record values it has.:param views: list of [view_id, view_type]:param dict options: a dict optional boolean flags, set to enable:``toolbar``includes contextual actions when loading fields_views``load_filters``returns the model's filters``action_id``id of the action to get the filters, otherwise loads the globalfilters or the model:return: dictionary with fields_views, fields and optionally filters"""

调用链条:
get_views => get_view => _get_view_cache => _get_view
重点看一下 _get_view这个私有函数:

 @api.modeldef _get_view(self, view_id=None, view_type='form', **options):"""Get the model view combined architecture (the view along all its inheriting views).:param int view_id: id of the view or None:param str view_type: type of the view to return if view_id is None ('form', 'tree', ...):param dict options: bool options to return additional features:- bool mobile: true if the web client is currently using the responsive mobile view(to use kanban views instead of list views for x2many fields):return: architecture of the view as an etree node, and the browse record of the view used:rtype: tuple:raise AttributeError:if no view exists for that model, and no method `_get_default_[view_type]_view` exists for the view type"""View = self.env['ir.ui.view'].sudo()# try to find a view_id if none providedif not view_id:# <view_type>_view_ref in context can be used to override the default viewview_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.viewview_id = View.default_view(self._name, view_type)if view_id:# read the view with inherited views appliedview = View.browse(view_id)arch = view._get_combined_arch()else:# fallback on default views methods if no ir.ui.view could be foundview = View.browse()try:arch = getattr(self, '_get_default_%s_view' % view_type)()except AttributeError:raise UserError(_("No default view of type '%s' could be found!", view_type))return arch, view

如果没有传入view_id, 那么就去上下文中查找_view_ref, 这给了我们一种思路,那就是可以在上下文中指定视图。
如果还是获取不到view_id,那么调用View.default_view函数获取默认的视图。
如果获取到了view_id, view返回该条记录,而arch返回处理好继承关系之后的结构

            view = View.browse(view_id)arch = view._get_combined_arch()

如果view_id 还是没有获取到,那么还是做了最后的尝试

arch = getattr(self, '_get_default_%s_view' % view_type)()

调用了视图类型对应的函数,以form为例,调用_get_default_form_view返回arch,如果没有这个函数,那就抛出异常。 odoo: 我已经尽了我最大的努力了。。。

1.4 view_ref 应用的案例

<page string="Analytic Lines" name="analytic_lines" groups="analytic.group_analytic_accounting"><field name="date" invisible="1"/><field name="analytic_line_ids" context="{'tree_view_ref':'analytic.view_account_analytic_line_tree', 'default_general_account_id':account_id, 'default_name': name, 'default_date':date, 'amount': (debit or 0.0)-(credit or 0.0)}"/>
</page>

随便找了 一个例子,这是一个x2many字段,在context中指定了 tree_view_ref,那么系统在打开的时候就会调用这里指定的tree视图,而不是默认的tree视图。

ir_ui_view.py的代码有3000行,这里只介绍了很少的一部分,后面如果有其他的知识点,再来补充。

1.5 _get_default_form_view

通过代码动态生成视图,这给了我们一共思路,就是在审批流中等需要动态生成视图的场景下,可以参考这种方式。
本质是动态生成或者改变arch,在后端或者前端都可以做。

@api.modeldef _get_default_form_view(self):""" Generates a default single-line form view using all fieldsof the current model.:returns: a form view as an lxml document:rtype: etree._Element"""sheet = E.sheet(string=self._description)main_group = E.group()left_group = E.group()right_group = E.group()for fname, field in self._fields.items():if field.automatic:continueelif field.type in ('one2many', 'many2many', 'text', 'html'):# append to sheet left and right group if neededif len(left_group) > 0:main_group.append(left_group)left_group = E.group()if len(right_group) > 0:main_group.append(right_group)right_group = E.group()if len(main_group) > 0:sheet.append(main_group)main_group = E.group()# add an oneline group for field type 'one2many', 'many2many', 'text', 'html'sheet.append(E.group(E.field(name=fname)))else:if len(left_group) > len(right_group):right_group.append(E.field(name=fname))else:left_group.append(E.field(name=fname))if len(left_group) > 0:main_group.append(left_group)if len(right_group) > 0:main_group.append(right_group)sheet.append(main_group)sheet.append(E.group(E.separator()))return E.form(sheet)

这篇关于odoo17核心概念view5——ir_ui_view.py的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/539035

相关文章

Python进阶之列表推导式的10个核心技巧

《Python进阶之列表推导式的10个核心技巧》在Python编程中,列表推导式(ListComprehension)是提升代码效率的瑞士军刀,本文将通过真实场景案例,揭示列表推导式的进阶用法,希望对... 目录一、基础语法重构:理解推导式的底层逻辑二、嵌套循环:破解多维数据处理难题三、条件表达式:实现分支

深度解析Python yfinance的核心功能和高级用法

《深度解析Pythonyfinance的核心功能和高级用法》yfinance是一个功能强大且易于使用的Python库,用于从YahooFinance获取金融数据,本教程将深入探讨yfinance的核... 目录yfinance 深度解析教程 (python)1. 简介与安装1.1 什么是 yfinance?

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

flask库中sessions.py的使用小结

《flask库中sessions.py的使用小结》在Flask中Session是一种用于在不同请求之间存储用户数据的机制,Session默认是基于客户端Cookie的,但数据会经过加密签名,防止篡改,... 目录1. Flask Session 的基本使用(1) 启用 Session(2) 存储和读取 Se

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1

WinForm跨线程访问UI及UI卡死的解决方案

《WinForm跨线程访问UI及UI卡死的解决方案》在WinForm开发过程中,跨线程访问UI控件和界面卡死是常见的技术难题,由于Windows窗体应用程序的UI控件默认只能在主线程(UI线程)上操作... 目录前言正文案例1:直接线程操作(无UI访问)案例2:BeginInvoke访问UI(错误用法)案例

Spring Boot Maven 插件如何构建可执行 JAR 的核心配置

《SpringBootMaven插件如何构建可执行JAR的核心配置》SpringBoot核心Maven插件,用于生成可执行JAR/WAR,内置服务器简化部署,支持热部署、多环境配置及依赖管理... 目录前言一、插件的核心功能与目标1.1 插件的定位1.2 插件的 Goals(目标)1.3 插件定位1.4 核

详解MySQL中DISTINCT去重的核心注意事项

《详解MySQL中DISTINCT去重的核心注意事项》为了实现查询不重复的数据,MySQL提供了DISTINCT关键字,它的主要作用就是对数据表中一个或多个字段重复的数据进行过滤,只返回其中的一条数据... 目录DISTINCT 六大注意事项1. 作用范围:所有 SELECT 字段2. NULL 值的特殊处

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实