主頁 > 後端開發 > odoo 權限管理學習總結

odoo 權限管理學習總結

2023-03-14 07:12:34 後端開發

環境

odoo-14.0.post20221212.tar

base_user_role-12.0.2.1.2.zip

下載地址:

https://apps.odoo.com/apps/modules/12.0/base_user_role/

權限管理

簡介

為了更好的熟悉權限,我們先來了解下用戶,odoo中的用戶分為三類:

  • 內部用戶(Internal User): 企業內部的用戶,擁有對系統內部的訪問權限,也就是說有odoo后端的訪問權限,
  • 門戶用戶(Portal): 非企業內部用戶,通常為業務合作伙伴用戶,擁有有限的資源訪問權限,
  • 公共用戶(Public): 面向公眾的權限,可以理解為游客權限,

提示:管理員登錄系統,激活開發者模式,即可在設定-用戶詳情頁對用戶型別進行編輯(Settings -> Users & Companies -> Users)

以上三類用戶的資訊都存在res_userres_partner表中,那么在odoo中如何區分用戶型別以及如何做權限控制的呢?

為了解決上述問題,odoo采用了用戶組機制,將用戶劃分為不同的組(一個用戶可以歸屬多個用戶組,一個用戶組也可以擁有多個用戶),然后給組分配權限,從而實作用戶權限的管控及用戶型別識別,

以上三種用戶分別歸屬以下用戶組:

  • 內部用戶:base.group_user
  • 門戶用戶:base.group_portal
  • 公共用戶:base.group_public

odoo也支持自定義用戶組(Settings -> Users & Companies -> Groups),并為用戶分配不同的用戶組,及設定相關權限(選單權限,視圖權限,訪問權限,記錄規則)

此外,為了更方便的管理用戶組,odoo還支持對用戶組(group)進行分類:將多個用戶組劃分為一個用戶組分類(category),

  • 用戶組和用戶組分類:一個用戶組分類可以擁有多個用戶組,一個用戶組僅歸屬一個用戶組分類,屬于1對多的關系,
  • 用戶組和用戶組的關系:用戶組可以被用戶組繼承(偽繼承),當繼承某個用戶組時,本組用戶也會自動加入繼承的用戶組,如果一個用戶屬于多個用戶組,那么該用戶權限為用戶組權限的并集,因此設計用戶組權限時一定要考慮好組與組之間權限是否會發生沖突,

定義用戶組(權限組)

示例:xml資料檔案的方式定義選單權限用戶組

<odoo>
    <data noupdate="1">
         <record id="estate_property_menu_groups" model="ir.module.category"><!-- id:供代碼或者xml中參考,model:odoo的category模型-->         
             <field name="name">[房地產]模塊選單權限</field><!--用戶組分類名稱--> 
             <field name="sequence">1</field><!--組分類顯示順序、優先級-->
         </record>

         <!--########################
         [房地產]模塊選單
         ########################-->
        <record id="group_estate_property_root_menu" model="res.groups">
            <field name="name">Real Estate</field><!--用戶組名稱,闡明組的角色/目的-->
            <field name="category_id" ref="estate_property_menu_groups"/><!--指定用戶組所屬組分類-->
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/><!--定義用戶組繼承自哪些組,也就是說該用戶組也擁有這些繼承組的權限-->
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/><!--為用戶組添加用戶 base.user_root root用戶 -->   
        </record>
    </data> 
</odoo>

說明:

noupdate:如果資料檔案的內容預期只應用一次(只加載一次,安裝或者更新模塊時),則可以將noupdate設定為1,如果檔案中的部分資料需要應用一次,則可以將檔案的這部分放在<data-noupdate="1">中,如下:

<odoo>
    <data noupdate="1">
        <!-- Only loaded when installing the module (odoo-bin -i module) -->
        <operation/>
    </data>
    <!-- (Re)Loaded at install and update (odoo-bin -i/-u) -->
    <operation/>
</odoo>

參考連接:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/data.html?highlight=noupdate

base.user_adminadmin用戶(ID為2的用戶,用戶資料定義在odoo\addons\base\data\res_users_data.xml

base.user_root__system__用戶(ID為1的用戶,technical admin )

category定義相關資料存盤在ir_module_category表中

添加的group,可以在Settings -> Users & Groups -> Groups界面看到,組定義相關資料存盤在res_groups表中

eval語法說明

  • (0, 0, values) 從提供的valueS字典創建新記錄,形如(0, 0, {'author': user_root.id, 'body': 'one'})
  • (2, ID, values) 使用values字典中的值更新id值=ID的現有記錄
  • (2, ID) 洗掉id=ID這條記錄(呼叫unlink方法,洗掉資料及整個主從資料鏈接關系)
  • (3, ID) 洗掉主從資料的鏈接關系但是不洗掉這個記錄
  • (4, ID) 為id=ID的資料添加主從鏈接關系
  • (5) 去除所有的鏈接關系,也就是回圈所有的從資料且呼叫(3,ID)
  • (6, 0, [IDs]) 用IDs中的記錄替換原來鏈接的記錄(相當于先執行(5)再回圈執行(4, ID)

拓展:

odoo中有個特殊的組base.group_no_one,需要開啟Debug模式才可獲取該組權限,可以利用該特性實作隱藏物件需求,比如針對一些常規下不需要顯示的特殊欄位,為其設定屬性groups = "base.group_no_one",可以實作在非Debug模式下隱藏欄位在視圖中的顯示,

選單訪問權限

應用實體

estate/security/security_estate_property_menu_groups.xml

<odoo>
    <data noupdate="1">
         <record id="estate_property_menu_groups" model="ir.module.category">
             <field name="name">[房地產]模塊選單權限</field>
             <field name="sequence">1</field>
         </record>

         <!--########################
         [房地產]模塊選單
         ########################-->
        <record id="group_estate_property_root_menu" model="res.groups">
            <field name="name">Real Estate</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_advertisements_menu" model="res.groups">
            <field name="name">Real Estate -> Advertisements</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_advertisements_properties_menu" model="res.groups">
            <field name="name">Real Estate -> Advertisements -> Properties</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
</odoo>

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[
        'security/security_estate_property_menu_groups.xml',
        //...略
    ]
}
選單配置

views/estate_menus.xml

<?xml version="1.0"?>
<odoo>
    <menuitem id="test_menu_root" name="Real Estate" web_icon="estate,static/img/icon.png"
    groups="group_estate_property_root_menu">
        <menuitem id="test_first_level_menu" name="Advertisements" groups="group_estate_property_advertisements_menu">
            <menuitem id="estate_property_menu_action" action="link_estate_property_action" groups="group_estate_property_advertisements_properties_menu"/>
            <!--略-->
        </menuitem>
        <!--略-->
    </menuitem>
</odoo>

查看效果

注意:

  1. 實踐時發現,通過界面點擊,訪問一些選單界面時,會在選單訪問URL(參見選單訪問自動生成的URL)中自動添加model,view_type等引數,也就是說會自動訪問模塊相關模型,如果此時沒有對應模型的訪問權限(至少需要 read權限),那么即便擁有對應選單的訪問權限,界面上也看不到對應的選單,筆者嘗試過在瀏覽器中直接通過選單鏈接(形如二級導航選單http://localhost:8888/web#action=85&cids=1&menu_id=127)訪問選單,發現界面上不會顯示任何選單,

    選單訪問自動生成的URL

    http://localhost:8888/web#action=85&model=estate.property&view_type=kanban&cids=1&menu_id=70
    
  2. 通過上述方式實作的選單訪問權限控制,實際是通過控制是否隱藏選單實作的,也就說,如果知道未授權選單ID,還是可以通過選單ID拼接選單URL進行未授權訪問,

模型訪問權限(Access Rights,表級別)

當模型中沒有定義任何訪問權限時,odoo會認為沒有任何用戶可以訪問資料,并在日志中列印:

2022-12-14 09:01:38,994 32508 WARNING odoo odoo.modules.loading: The model estate.property has no access rules, consider adding one. E.g. access_estate_property,access_estate_property,model_estate_property,base.group_user,1,0,0,0 

訪問權限被定義為ir.model.access 模型記錄,每個訪問權限關聯一個模型,一個group(針對全域訪問,沒有組) 和一系列權限:create, read, writeunlink(等同于delete),這些訪問權限通常定義在security/ir.model.access.csv檔案中,

test.model模型訪問權限配置示例

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_test_model,access_test_model,model_test_model,base.group_user,1,0,0,0
  • id 自定義外部標識,模塊中保持唯一,一般命名為 access_模型名稱_用戶組名稱
  • name 自定義ir.model.access的名稱,一般命名沿用id取值即可
  • model_id/idmodel_id:id 代指需要應用訪問權限的模型,標準格式為 model_<model_name>,其中, <model_name>為模塊中_name 替換._后的_name 的值
  • group_id/idgroup_id:id 代指需應用訪問權限的組,即指定哪個組擁有如下訪問權限,如果指定組不是在當前模塊中定義的組,需要指定模塊名稱,形如module_name.groupName,組名一般命名為group_模型名稱_權限,形如group_estate_property_read ,如果 group_id為空,則意味著授權給所有用戶(非雇員(employees) ,比如 portal 或者public用戶).
  • perm_read,perm_write,perm_create,perm_unlink: 分別代表create(創建), read(只讀/查詢), write (編輯/更新)和unlink(洗掉)權限,1表示有訪問權限,0-表示無權限

具體到實際應用時,為了更靈活的權限管理,一般會為模型的增刪改查操作分別定義權限,

授權給用戶的模型訪問權限,可通過點擊Settings -> Users & Groups -> Users用戶詳情頁Access Rights按鈕查看,

應用實體

xml資料檔案的方式定義房地產模型訪問權限

estate/security/security_estate_property_model_groups.xml

<odoo>
    <data noupdate="1">
         <record id="estate_property_model_groups" model="ir.module.category">
             <field name="name">[房地產]模型權限</field>
             <field name="sequence">1</field>
         </record>


         <!--########################
         [房地產]模型
         ########################-->
        <!-- [房地產]模型 增刪改查 -->
        <record id="group_estate_property_read" model="res.groups">
            <field name="name">[房地產]模型 只讀</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_write" model="res.groups">
            <field name="name">[房地產]模型 更新</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_create" model="res.groups">
            <field name="name">[房地產]模型 創建</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_delete" model="res.groups">
            <field name="name">[房地產]模型 洗掉</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
</odoo>

estate/security/ir.model.access.csv

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_estate_property_group_estate_property_read,access_estate_property_group_estate_property_read,model_estate_property,group_estate_property_read,1,0,0,0
access_estate_property_group_estate_property_write,access_estate_property_group_estate_property_write,model_estate_property,group_estate_property_write,1,1,0,0
access_estate_property_group_estate_property_create,access_estate_property_group_estate_property_create,model_estate_property,group_estate_property_create,1,0,1,0
access_estate_property_group_estate_property_delete,access_estate_property_group_estate_property_delete,model_estate_property,group_estate_property_delete,1,0,0,1

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[
        'security/security_estate_property_menu_groups.xml',
        'security/security_estate_property_model_groups.xml',
        'security/ir.model.access.csv', 
        //...略
    ]
}
查看效果

打開用戶編輯界面

記錄規則(Record Rules,記錄級別)

記錄規則是允許某個操作必須滿足的條件,記錄規則按照訪問權限逐條記錄評估,

默認允許的記錄規則:如果授予模型訪問權限(Access Rights),并且沒有規則適用于用戶的操作和模型,則授予訪問權限

記錄規則保存在ir.rule模型表里,我們通過管理ir_rule表中的記錄,即可控制記錄的訪問權限

定義規則

示例:xml資料檔案的方式定義房地產模型記錄訪問規則

<odoo>
    <data noupdate="0">
        <!--########################
        [房地產]模型記錄規則
        ########################-->
        <record id="estate_property_record_read_rule" model="ir.rule"><!--id:外部規則id,供代碼或者xml中參考 -->
            <field name="name">[房地產]模型記錄規則</field>
            <field name="model_id" ref="model_estate_property"/>
            <field name="domain_force">[('create_uid', '=', user.id)]</field><!--僅顯示用戶自己創建的記錄-->
            <field name="groups" eval="[(4, ref('group_estate_property_record_read'))]"/>
            <!--操作權限(僅作用于經domain_force濾后的記錄)-->
            <field name="perm_read" eval="1"/>
            <field name="perm_write" eval="1"/>
            <field name="perm_create" eval="1"/>
            <field name="perm_unlink" eval="1"/>
        </record>
    </data>
</odoo>
  • name

    規則名稱

  • model_id

    需要應用規則的模型,標準格式為 model_<model_name>,其中, <model_name>為模塊中_name 替換._后值

  • groups

    指定規則需要作用、不作用于哪些組(res.groups),可以指定多個組,如果未指定組,規則為gobal規則,規則與組的關聯關系存在rule_group_rel表中

  • global

    根據“groups”計算,提供了對規則是否全域狀態的輕松訪問,eval="True"eval="1"則表示全域規則,eval="False"eval="0"則表示非全域規則

  • domain_force

    指定為 domain的謂詞,如果該domain與記錄匹配,則規則允許所選操作,否則禁止,可以簡單的理解為指定過濾條件,用戶只能訪問符合本過濾條件的記錄,配置為 [(1,'=',1)]則表示匹配所有記錄,domain是一個可以使用以下變數的python運算式:

    • time

      Python的 time 模塊

    • user

      以單例記錄集(singleton recordset)表示的當前用戶

    • company_id

      當前用戶,當前所選的公司的公司id(非記錄集),

    • company_ids

      當前用戶可以訪問的公司ID串列(非記錄集), 查看Security rules 獲取更多詳細資訊,

官方檔案:

The perm_method have completely different semantics than for ir.model.access: for rules, they specify which operation the rules applies for. If an operation is not selected, then the rule is not checked for it, as if the rule did not exist.

All operations are selected by default

譯文:

perm_method 具有與 ir.model.access完全不同的語意:對于規則,它們指定規則需要應用的操作,如果(規則)未選擇某個操作,則不會為該操作檢查規則,就像該規則不存在一樣,

規則默認適用所有操作,

筆者實踐發現:

  • 如果創建了規則,但是沒有授權給用戶,那對于該用戶來說,該規則不起作用,就像該規則不存在一樣
  • perm_methodeval值不能同時為"False""0",否則會違反 ir_rule表的檢查約束ir_rule_no_access_rightsCHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False)
  • 將任意一個perm_method設定為eval="True"eval="1" ,并將規則授權給用戶,規則生效,所以我個人理解,目前記錄規則,就是用于過濾記錄的,通過domain_force控制哪些記錄可以顯示給用戶

規則默認適用所有操作,

  • perm_create

  • ``perm_read`

  • perm_write

  • perm_unlink

  • 授權給用戶的記錄訪問規則,可通過點擊Settings -> Users & Groups -> Users用戶詳情頁Record Rules按鈕查看,

全域規則(Global rules) VS 組規則(group rules)

全域規則和組規則在組成和組合方式上存在很大差異:

  • 全域規則和全域規則之間取交集,如果兩個全域規則都生效,則必須滿足兩者才能授予訪問權限,這意味著添加全域規則總是會進一步限制訪問,
  • 組規則和組規則之間取并集,如果兩個組規則都生效,則滿足其中之一就可以授予訪問權限,這意味著添加組規則可以擴展訪問,但不能超出全域規則定義的范圍,
  • 全域規則集和組規則集之間取交集,這意味著添加到給定全域規則集的第一個組規則將限制訪問,

危險提示

創建多個全域規則是有風險的,因為可能創建不重疊的規則集,這將洗掉所有訪問權限

應用實體

estate/security/security_estate_property_model_groups.xml,新增group_estate_property_record_query

<odoo>
    <data noupdate="1">
         <record id="estate_property_model_groups" model="ir.module.category">
             <field name="name">[房地產]模型權限</field>
             <field name="sequence">1</field>
         </record>


         <!--########################
         [房地產]模型
         ########################-->
        <!-- [房地產]模型 增刪改查 -->
        <record id="group_estate_property_read" model="res.groups">
            <field name="name">[房地產]模型 只讀</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_write" model="res.groups">
            <field name="name">[房地產]模型 更新</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_create" model="res.groups">
            <field name="name">[房地產]模型 創建</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_delete" model="res.groups">
            <field name="name">[房地產]模型 洗掉</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
  
    <data noupdate="0">
        <!--########################
         [房地產]模型記錄
         ########################-->
        <record id="group_estate_property_record_query" model="res.groups">
            <field name="name">[房地產]模型記錄 查詢</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>       
    </data>
</odoo>

estate/security/security_estate_property_model_record_rules.xml

<odoo>
    <data noupdate="0">
        <!--########################
        [房地產]模型記錄規則
        ########################-->
        <record id="estate_property_record_read_rule" model="ir.rule">
            <field name="name">[房地產]模型記錄規則</field>
            <field name="model_id" ref="model_estate_property"/>
            <field name="domain_force">[('create_uid', '=', user.id)]</field>
            <field name="groups" eval="[(4, ref('group_estate_property_record_read'))]"/>
            <field name="perm_read" eval="1"/>
            <field name="perm_write" eval="1"/>
            <field name="perm_create" eval="1"/>
            <field name="perm_unlink" eval="1"/>
        </record>
    </data>
</odoo>

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[        
        'security/security_estate_property_menu_groups.xml',
        'security/security_estate_property_model_groups.xml',
        'security/security_estate_property_model_record_rules.xml',
        'security/ir.model.access.csv',
        //...略
    ]
}

查看效果

參考連接:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html#record-rules

欄位權限(Field Access,欄位級別)

ORM欄位可以具有提供組串列的groups屬性(值為逗號分隔的組XML ID串列,如groups='base.group_user,base.group_system'注意:groups屬性值格式:moduleName.groupName,其中moduleNamegroupName組所在模塊名稱,必不可少

如果當前用戶不在列出的組中,他將無權訪問該欄位:

  • 將自動從請求的視圖中洗掉受限制的欄位
  • fields_get()回應中洗掉受限制的欄位

嘗試(顯式的)讀取或寫入受限欄位會導致訪問錯誤

修改estate\security\security_estate_property_model_groups.xml,添加group_estate_property_selling_price_field

    <data noupdate="0">
        <!--########################
         [房地產]模型記錄
         ########################-->
        <record id="group_estate_property_selling_price_field" model="res.groups">
            <field name="name">[房地產]模型 售價欄位</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
        <record id="group_estate_property_record_query" model="res.groups">
            <field name="name">[房地產]模型記錄 查詢</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>

查看效果

修改estate\views\estate_property_views.xml視圖selling_price欄位,添加groups屬性

<field name="selling_price" string="Selling Price" groups="estate.group_estate_property_selling_price_field"/>

驗證,發現界面上,未授權上述框選權限的用戶已經看不到上述欄位了

注意:通過為當前視圖中目標欄位添加groups屬性實作的權限控制僅作用于當前視圖,如果希望當前視圖模型(Model)的所有視圖中,對該欄位實作統一的權限控制話,需要在模型定義中,為目標欄位添加groups屬性,如下

selling_price = fields.Float('selling price', digits=(8, 2), readonly=True, copy=False, groups="estate.group_estate_property_selling_price_field")

參考連接:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html#field-access

擴展:在頁面從資料庫加載視圖時,會通過load_view介面,會呼叫fields_view_get方法,可以重寫此方法以控制xml顯示的效果(參考網路資料,未實踐驗證)

按鈕權限(按鈕級別)

類似欄位權限控制,僅需在在對應視圖中,為目標按鈕<button>元素,添加groups屬性即可,

角色定義

新增并安裝base_user_role模塊

base_user_role模塊的作用可以簡單理解為,按自定義維度將所需權限組組合在一起,組成角色,實作批量授權的功能,

解壓下載的base_user_role-12.0.2.1.2.zip檔案,對解壓后的部分檔案做如下修改:

base_user_role\models\user.pybase_user_role\models\role.py

去除上述兩個檔案中的所有@api.multi修飾符,解決安裝報錯問題:

AttributeError: module 'odoo.api' has no attribute 'multi'

說明:Odoo 13.0開始,移除multimulti作為默認實作,

base_user_role/views/role.xml

修改

<record model="ir.actions.act_window" id="action_res_users_role_tree">
    <field name="name">Roles</field>
    <field name="type">ir.actions.act_window</field>
    <field name="res_model">res.users.role</field>
    <field name="view_type">form</field>
    <field name="view_id" ref="view_res_users_role_tree"/>
</record>

<record model="ir.actions.act_window" id="action_res_users_role_tree">
    <field name="name">Roles</field>
    <field name="type">ir.actions.act_window</field>
    <field name="res_model">res.users.role</field>
    <field name="view_mode">form</field>
    <field name="view_id" ref="view_res_users_role_tree"/>
</record>

解決安裝報錯問題:

odoo.tools.convert.ParseError: while parsing file:/d:/codepojects/odoo14/custom/base_user_role/views/role.xml:63, near

然后,將解壓目錄下base_user_role整個檔案夾拷貝odoo14\custom目錄下,最后,重啟服務并安裝該模塊,

安裝成功后,Settings -> Users & Companies選單下,將新增Roles子選單(筆者實踐發現無法通過該頁面新增角色并關聯用戶),Settings -> Users & Companies -> Users 用戶記錄詳情頁將新增Roles Tab頁

新增并安裝estate_role模塊

為了統一管理權限組,考慮新增一個單獨的應用模塊estate_role,模塊檔案組織結構如下

custom/estate_role
│  __init__.py
│  __manifest__.py
│
├─security
│      security_estate_property_menu_groups.xml
│      security_estate_property_model_groups.xml
│      security_roles.xml
│
└─views

odoo14\custom\estate_role\security\security_roles.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data noupdate="1">
        <record id="group_role_base_user" model="res.users.role">
            <field name="name">基礎用戶</field>
            <field name="implied_ids" eval="[
                    (4, ref('base.group_user')),
                ]"/>
        </record>

        <record id="group_role_multi_company" model="res.users.role">
            <field name="name">多公司</field>
            <field name="implied_ids" eval="[
                    (4, ref('base.group_multi_company')),
                ]"/>
        </record>

        <record id="group_role_devops" model="res.users.role">
            <field name="name">運維</field>
            <field name="implied_ids" eval="[
                    (4, ref('estate_role.group_estate_property_root_menu')),
                    (4, ref('estate_role.group_estate_property_advertisements_menu')),
                    (4, ref('estate_role.group_estate_property_advertisements_properties_menu')),
                    (4, ref('estate_role.group_estate_property_read')),
                    (4, ref('estate_role.group_estate_property_write')),
                    (4, ref('estate_role.group_estate_property_create'))
                ]"/>
        </record>
    </data>
</odoo>

odoo14\custom\estate_role\__init__.py

檔案內容為空

odoo14\custom\estate_role\__manifest__.py

{
    "name": "Estate Roles",
    "license": "LGPL-3",
    "depends": ["base_user_role"],
    "data": [
        "security/security_estate_property_menu_groups.xml",
        "security/security_estate_property_model_groups.xml",
        "security/security_roles.xml"
    ],
    "installable": True,
}

說明:odoo14\custom\estate\__manifest__.py data串列中已去除上述兩個groups檔案

重啟服務并安裝estate_role模塊

查看效果

用戶詳情頁面,查看用戶權限,發現新增 User Roles

編輯用戶,勾選圖中的角色,保存,發現和角色關聯的權限組都會被自動勾選了,

注意:

  • 取消勾選已授予的角色,并保存,不會自動取消勾選角色關聯的權限組,即取消授予角色操作,不會取消通過授予角色授予給用戶的權限組
  • 已授予角色給用戶的情況下,取消勾選某個權限組并保存,如果該權限組和授予給用戶的角色關聯,則無法取消勾選的權限組,因為角色關聯了該權限組
  • 權限頁面勾選并保存的角色,不會在用戶詳情頁的Roles Tab頁中顯示
  • 除了通過在用戶詳情頁-權限(Access Rights)Tab頁面,選取角色為用戶批量授權外,還可以在用戶詳情頁的Roles Tab頁中為用戶添加角色來實作批量授權,

參考連接

https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html

作者:授客
微信/QQ:1033553122
全國軟體測驗QQ交流群:7156436

Git地址:https://gitee.com/ishouke
友情提示:限于時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支持將是我繼續創作的源動力,打賞后如有任何疑問,請聯系我!!!
           微信打賞                        支付寶打賞                  全國軟體測驗交流QQ群  
              

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/546672.html

標籤:Python

上一篇:FastAdmin的API介面生成器插件,使用validate驗證時報錯等問題。

下一篇:Pycharm 簡介

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more