odoo12 用户(users) 权限管理界面分析

2023-11-11

起因:

由于需要了解 odoo的权限管理,去看了下 odoo 是如何给用户赋权限的。发现好多不能理解。因此,打算从 user 的xml开始。看里面到底是什么意思

第一步,肯定查看user的xml。找user源码

odoo/odoo/addons/base/views/res_users_views.xml

  <record id="view_users_form" model="ir.ui.view">
            <field name="name">res.users.form</field>
            <field name="model">res.users</field>
            <field name="arch" type="xml">
                <form string="Users">
                    <header>
                    </header>
                    <sheet>
                        由于只看权限,这里全部省略....
                        <notebook colspan="4">
                            <page name="access_rights" string="Access Rights">
                                <group string="Multi Companies" attrs="{'invisible': [('companies_count', '&lt;=', 1)]}">
                                    <field string="Allowed Companies" name="company_ids" widget="many2many_tags" options="{'no_create': True}"/>
                                    <field string="Current Company" name="company_id" context="{'user_preference': 0}"/>
                                    <field string="Companies count" name="companies_count" invisible="1"/>
                                </group>
                                <field name="groups_id"/>
                            </page>
                            <page string="Preferences">
                                省略......
                            </page>
                        </notebook>
                    </sheet>
                </form>
            </field>
        </record>

发现。里面根本没有 权限部分的代码。。然后找了继承view_users_form ,发现也没有。想想也对,既然权限是动态生成的,肯定要在后台完成,不会在 前台写固定的。

由于增删改都需要更新界面。所以 查看user的后台代码。找到

 @api.model
    def _update_user_groups_view(self):
        """ Modify the view with xmlid ``base.user_groups_view``, which inherits
            the user form view, and introduces the reified group fields.
        """

        # remove the language to avoid translations, it will be handled at the view level
        self = self.with_context(lang=None)

        # We have to try-catch this, because at first init the view does not
        # exist but we are already creating some basic groups.
        # 获取 base.user_groups_view 组view 的xml
        view = self.env.ref('base.user_groups_view', raise_if_not_found=False)
        if view and view.exists() and view._name == 'ir.ui.view':
            group_no_one = view.env.ref('base.group_no_one')
            group_employee = view.env.ref('base.group_user')
            xml1, xml2, xml3 = [], [], []
            # 这两个固定
            xml1.append(E.separator(string='User Type', colspan="2", groups='base.group_no_one'))
            xml2.append(E.separator(string='Application Accesses', colspan="2"))

            user_type_field_name = ''
            for app, kind, gs in self.get_groups_by_application():
                attrs = {}
                # hide groups in categories 'Hidden' and 'Extra' (except for group_no_one)
                if app.xml_id in ('base.module_category_hidden', 'base.module_category_extra', 'base.module_category_usability'):
                    attrs['groups'] = 'base.group_no_one'

                # User type (employee, portal or public) is a separated group. This is the only 'selection'
                # group of res.groups without implied groups (with each other).
                if app.xml_id == 'base.module_category_user_type':
                    # application name with a selection field
                    field_name = name_selection_groups(gs.ids)
                    user_type_field_name = field_name
                    attrs['widget'] = 'radio'
                    attrs['groups'] = 'base.group_no_one'
                    xml1.append(E.field(name=field_name, **attrs))
                    xml1.append(E.newline())

                elif kind == 'selection':
                    # 只要属于selection 的就放在Application Accesses 下
                    # application name with a selection field
                    field_name = name_selection_groups(gs.ids)
                    xml2.append(E.field(name=field_name, **attrs))
                    xml2.append(E.newline())
                else:
                    # application separator with boolean fields
                    # 不属于那两个的则为 app_name
                    app_name = app.name or 'Other'
                    xml3.append(E.separator(string=app_name, colspan="4", **attrs))
                    for g in gs:
                        field_name = name_boolean_group(g.id)
                        if g == group_no_one:
                            # make the group_no_one invisible in the form view
                            xml3.append(E.field(name=field_name, invisible="1", **attrs))
                        else:
                            xml3.append(E.field(name=field_name, **attrs))

            xml3.append({'class': "o_label_nowrap"})
            if user_type_field_name:
                user_type_attrs = {'invisible': [(user_type_field_name, '!=', group_employee.id)]}
            else:
                user_type_attrs = {}

            xml = E.field(
                E.group(*(xml1), col="2"),
                E.group(*(xml2), col="2", attrs=str(user_type_attrs)),
                E.group(*(xml3), col="4", attrs=str(user_type_attrs)), name="groups_id", position="replace")
            xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS"))
            xml_content = etree.tostring(xml, pretty_print=True, encoding="unicode")

            new_context = dict(view._context)
            new_context.pop('install_mode_data', None)  # don't set arch_fs for this computed view
            new_context['lang'] = None
            # 写入base.user_groups_view
            view.with_context(new_context).write({'arch': xml_content})

可以看到。完全在后台给生成了。。都有注释。只说大概原理

<record id="user_groups_view" model="ir.ui.view">
            <field name="name">res.users.groups</field>
            <field name="model">res.users</field>
            <field name="inherit_id" ref="view_users_form"/>
            <field name="arch" type="xml">
                <!-- dummy, will be modified by groups -->
                <field name="groups_id" position="after"/>
            </field>
        </record>

1、先获取user_groups_view,的view。。而此view 继承 users_form ,而且after

2、根据逻辑生成 content 。然后 写入数据库的 arch里面就ok了

 

还有个疑问,如何 确定  selection

    def get_groups_by_application(self):
        """ Return all groups classified by application (module category), as a list::

                [(app, kind, groups), ...],

            where ``app`` and ``groups`` are recordsets, and ``kind`` is either
            ``'boolean'`` or ``'selection'``. Applications are given in sequence
            order.  If ``kind`` is ``'selection'``, ``groups`` are given in
            reverse implication order.
        """
        #  app 分类  gs 组
        def linearize(app, gs):
            # 'User Type' is an exception 特例  app.xml_id 是计算字段
            if app.xml_id == 'base.module_category_user_type':
                return (app, 'selection', gs.sorted('id'))
            # determine sequence order: a group appears after its implied groups  自己继承的组
            order = {g: len(g.trans_implied_ids & gs) for g in gs}
            # check whether order is total, i.e., sequence orders are distinct
            #判断当前group 是否有平级关系,没有平级关系的话,res_groups_implied_rel 肯定无数据,set{g:0,g:0}
            # /set{g:1,g:2,g:1} 肯定不等于gs(组对象)
            if len(set(order.values())) == len(gs):
                return (app, 'selection', gs.sorted(key=order.get))
            else:
                return (app, 'boolean', gs)

        # classify all groups by application
        by_app, others = defaultdict(self.browse), self.browse()
        # 遍历所有group
        for g in self.get_application_groups([]):
            if g.category_id:
                #如果有 category
                by_app[g.category_id] += g
            else:
                others += g
        # build the result
        res = []
        for app, gs in sorted(by_app.items(), key=lambda it: it[0].sequence or 0):
            #app 分类  gs 组
            res.append(linearize(app, gs))
        if others:
            res.append((self.env['ir.module.category'], 'boolean', others))
        return res

关键点在  order = {g: len(g.trans_implied_ids & gs) for g in gs}

trans_implied_ids = fields.Many2many('res.groups', string='Transitively inherits',
    compute='_compute_trans_implied')

@api.depends('implied_ids.trans_implied_ids')
def _compute_trans_implied(self):
    # Compute the transitive closure recursively. Note that the performance
    # is good, because the record cache behaves as a memo (the field is
    # never computed twice on a given group.)
    for g in self:
        g.trans_implied_ids = g.implied_ids | g.mapped('implied_ids.trans_implied_ids')

可以看出。trans_implied_ids 其实就是只想自己的 也就是 res_groups_implied_rel 。

只有当前 category 的组 和 trans_implied_ids  不重复的id 相等,才会显示selection

a -----b

---------c

平级 则不会

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

odoo12 用户(users) 权限管理界面分析 的相关文章

随机推荐

  • clang 01.clang简介

    文章目录 前言 1 Clang的工作流程 前言 Clang的官方网站是 http clang llvm org 它被认为是C家族的LLVM前端 Clang可能指代三种不同的实体 前端 由Clang程序库实现 编译器驱动器 由Clang命令和
  • 本机如何传文件到VMware 中

    本机传文件到VMware 中可以使用2种方法 1 安装tools 直接拖拽过去 2 实现文件共享 在VMware中没有安装解压文件的应用时 使用tools会不再适用 这时可以选择共享文件夹的方式 直接在本机解压文件 共享文件夹到VMware
  • C#中的Dispose模式

    声明 本文中的内容属于个人总结整理而来 个人水平有限 对于部分细节难免有理解错误及遗漏之处 如果您在阅读过程中有所发现 希望您能指正 同时文章中的部分内容也参考了其它大神的文章 如果文章中的内容侵犯了您的权益 表示非常歉意 请您指出 我将尽
  • C++职工管理系统

    C 演讲比赛流程管理系统 1 职工管理系统的需求 2 功能实现 2 1 创建管理类 2 2退出功能 2 3增加联系人信息 2 4显示职工信息 2 5删除离职职工 2 6修改职工信息 2 7查找职工信息 2 8按照编号排序 2 9清空所有文档
  • access建立er图_5G SA注册流程(2)- RRC连接建立

    导读 在正式讨论SA注册的相关NAS流程之前 笔者觉得有必要先讨论下SA下的RRC连接的建立流程 毕竟这是终端与网络交互的连接基础 同时也会讨论下不同场景下的RRC建立流程中信令内容的异同 RRC连接建立流程 SA注册流程主要是终端与5GC
  • 8X8X8光立方整体框架设计&技术细节

    从一师兄那拿来的 东西是师兄自己做的 觉得特有才一人 只是进了互联网公司 感觉做嵌入式更适合他 Powered by lihui Liusheng 2012 Shenyang 太过技术了 写给自己留着看的 不懂的可绕行 确实有些头大 在对最
  • OA权限树搭建 代码

    ul ul
  • Android下拉刷新效果实现

    本文主要包括以下内容 自定义实现pulltorefreshView 使用google官方SwipeRefreshLayout 下拉刷新大致原理 判断当前是否在最上面而且是向下滑的 如果是的话 则加载数据 并更新界面 自定义实现pulltor
  • Matlab中dir使用中遇到的一些问题

    今天调程序时遇到一个bug 感觉有点意思 也许有人会遇到类似的问题吧 问题 说手上有一段代码 原本是希望在一个文件夹中读取出其中所有音频文件的 tdir dir fullfile SoundDir SoundFileName NumSoun
  • 出现command 'gcc' failed with exit status 1 解决方案

    在centos7 上用pip 安装psutil的时候很不幸的出现了如下错误 pip install psutil Collecting psutil Using cached psutil 5 3 1 tar gz Installing c
  • python 角度判断_大牛带你打牢Python基础,看看这10语法

    都说Python简单 易懂 但是有时候却又很深奥 许多人都觉的自己学会了 却老是写不出项目来 对很多常用包的使用也并不熟悉 学海无涯 我们先来了解一些Python中最基本的内容 1 数值 数值包括整型和浮点型 分别对应整数和浮点数 后者精度
  • Python3 列表笔记

    列表 使用 括起来的一个个元素的集合 1 列表的元素使用 进行分割 2 列表的元素可以是任意数据类型 1 创建列表 list huarzil 32 3 14 True zhuangsan lisi 32 29 30 name height
  • linux学习笔记--网络编程

    目录 概念 协议 网络应用设计模式 分层模型 协议格式 TCP状态 网络名词 socket编程 套接字 字节序 函数 socket bind listen accept connect C S模型 server client 封装 高并发服
  • iview 数据表格 固定列拉倒底部后刷新出现错行问题

    很多小伙伴肯定遇到过这个组件问题 下面只需要一行即可搞定 vue方法 首先我们在mixin js里封装一个方法 pageSizeChange pageSize 每页显示数量变更 this searchParams limit pageSiz
  • C#中,浮点数的比较和decimal

    浮点数 C 的浮点数类型 float double 当我们定义一个浮点数可以 可以使用var 关键字 可以做类型推断 定义float类型 数字末尾需要加上 F或者是f 定义一个double类型 double a1 1 1 var a2 1
  • <转>企业应用架构 --- 分层

    系统架构师 基础到企业应用架构 分层 上篇 一 前言 大家好 接近一年的时间没有怎么书写博客了 一方面是工作上比较忙 同时生活上也步入正轨 事情比较繁多 目前总算是趋于稳定 可以有时间来完善以前没有写完的系列 也算是对自己这段时间工作和生活
  • 程序流程图是什么?基本流程图讲解

    程序流程图是什么 程序流程图是流程图的其中一种分类 又称程序框图 指用特定图形符号加上对应的文字描述表示程序中所需要的各项操作或判断的图示 程序流程图除了说明程序的流程顺序外 着重于说明程序的逻辑性 一 程序流程图特点 当程序流程中有较多循
  • 动态规划经典例题-国王的金矿问题

    金矿问题 问题概述 有一位国王拥有5座金矿 每座金矿的黄金储量不同 需要参与挖掘的工人人数也不同 例如有的金矿储量是500kg黄金 需 要5个工人来挖掘 有的金矿储量是200kg黄金 需要3个工人来挖 掘 如果参与挖矿的工人的总数是10 每
  • 转:FindBugs,第 2 部分: 编写自定义检测器

    FindBugs 第 2 部分 编写自定义检测器 如何编写自定义检测器以查找特定于应用程序的问题 FindBugs 是一种可以扩展和定制以满足自己团队独特要求的静态分析工具 在本系列的第 2 部分中 高级软件工程师 Chris Grinds
  • odoo12 用户(users) 权限管理界面分析

    起因 由于需要了解 odoo的权限管理 去看了下 odoo 是如何给用户赋权限的 发现好多不能理解 因此 打算从 user 的xml开始 看里面到底是什么意思 第一步 肯定查看user的xml 找user源码 odoo odoo addon