zoukankan      html  css  js  c++  java
  • 【odoo14】【知识点】视图的继承逻辑

    背景:同一个模块,两组开发人员对同一个模型的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'))
    

    结束

    本文来自博客园,作者:老韩头的开发日常,转载请注明原文链接:https://www.cnblogs.com/xushuotec/p/14833632.html

  • 相关阅读:
    linux运维工程师工作中的一些常见问题解决方法 风行天下
    64位win10系统无法安装.Net framework3.5的两种解决方法 风行天下
    vsphere使用笔记 风行天下
    kvm安装及使用 风行天下
    Linux 安装MySql 5.7.21 操作步骤 风行天下
    去掉mapxtreme for java 的水印
    在MapXtreme for Java 4.8.0 中发布新制作的电子地图
    NetBeans中Tomcat服务器中的manager 为什么不能浏览呢?
    VS2008简体中文正式版序列号及破解方法
    MAPXTREME FOR JAVA中中文显示问题
  • 原文地址:https://www.cnblogs.com/xushuotec/p/14833632.html
Copyright © 2011-2022 走看看