odoo17核心概念view5——ir_ui_view.py

2023-12-26 10:20
文章标签 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/539053

相关文章

在 PyQt 加载 UI 三种常见方法

《在PyQt加载UI三种常见方法》在PyQt中,加载UI文件通常指的是使用QtDesigner设计的.ui文件,并将其转换为Python代码,以便在PyQt应用程序中使用,这篇文章给大家介绍在... 目录方法一:使用 uic 模块动态加载 (不推荐用于大型项目)方法二:将 UI 文件编译为 python 模

Java Jackson核心注解使用详解

《JavaJackson核心注解使用详解》:本文主要介绍JavaJackson核心注解的使用,​​Jackson核心注解​​用于控制Java对象与JSON之间的序列化、反序列化行为,简化字段映射... 目录前言一、@jsonProperty-指定JSON字段名二、@JsonIgnore-忽略字段三、@Jso

一文带你搞懂Python中__init__.py到底是什么

《一文带你搞懂Python中__init__.py到底是什么》朋友们,今天我们来聊聊Python里一个低调却至关重要的文件——__init__.py,有些人可能听说过它是“包的标志”,也有人觉得它“没... 目录先搞懂 python 模块(module)Python 包(package)是啥?那么 __in

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

SpringQuartz定时任务核心组件JobDetail与Trigger配置

《SpringQuartz定时任务核心组件JobDetail与Trigger配置》Spring框架与Quartz调度器的集成提供了强大而灵活的定时任务解决方案,本文主要介绍了SpringQuartz定... 目录引言一、Spring Quartz基础架构1.1 核心组件概述1.2 Spring集成优势二、J

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

一文教你Python引入其他文件夹下的.py文件

《一文教你Python引入其他文件夹下的.py文件》这篇文章主要为大家详细介绍了如何在Python中引入其他文件夹里的.py文件,并探讨几种常见的实现方式,有需要的小伙伴可以根据需求进行选择... 目录1. 使用sys.path动态添加路径2. 使用相对导入(适用于包结构)3. 使用pythonPATH环境

Linux find 命令完全指南及核心用法

《Linuxfind命令完全指南及核心用法》find是Linux系统最强大的文件搜索工具,支持嵌套遍历、条件筛选、执行动作,下面给大家介绍Linuxfind命令完全指南,感兴趣的朋友一起看看吧... 目录一、基础搜索模式1. 按文件名搜索(精确/模糊匹配)2. 排除指定目录/文件二、根据文件类型筛选三、时间

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex