起因:
odooの権限管理を理解する必要があるため、odooがユーザーに権限を付与する方法を確認しました。わからないことがたくさん見つかりました。したがって、ユーザーのxmlから開始する予定です。内部の意味を見る
最初のステップは、ユーザーのxmlを確認することです。ユーザーのソースコードを探す
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', '<=', 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を探しましたが、何も見つかりませんでした。パーミッションは動的に生成されるため、バックグラウンドで実行する必要があり、フォアグラウンドで修正されることはありません。
追加、削除、変更のため、インターフェースを更新する必要があります。したがって、ユーザーのコードビハインドを確認してください。現れる
@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のビューを取得します。。そして、このビューはusers_formを継承し、その後
2.ロジックに従ってコンテンツを生成します。次に、データベースのアーチに書き込みます。それで問題ありません。
まだ質問があります、選択を決定する方法
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です。
現在のカテゴリのグループとtrans_implied_idsのIDが等しい場合にのみ、選択内容が表示されます
a ----- b
--------- c
等しくない