odoo res.config.settings 解析

res.config.setting:源码的解释是:继承自瞬态模型,应用程序设置的基本配置向导。它支持设置默认值、为员工用户分配组和安装模块。

也许你会有疑问:瞬态模型怎么保存数据?

其实他的数据保存机制都是通过调用一些方法,保存在其他模型里面,例如 res_groups,

ir_default ...

接下来让我们看一下这个模型如何使用:

目录

1、默认值

2、安装或者卸载模块

3、设置系统参数

4、设置用户组

5、源码分析

_get_classified_fields方法

execute方法:


1、默认值

比如说你有一个模型有一个字段设置了他创建时候默认值,即default属性,但是对于某些场景它需要另一个default属性,这时通过继承res.config.settings模型,配置这个字段的默认值选项,该字段以default_开头,属于一个全局默认值,就以原生的销售模块的一个继承模型为例:

然后这个代码在前端界面的体现:

用法:

例如在如下区域为自定义模型的某个字段设置默认值:

 实现效果:

 

demo.py:

from odoo import fields, models

class Demo(models.Model):
    _name = 'demo'
    name = fields.Char('默认值', default='aaa')

res_config_settings.py

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _

class ResConfigSettings(models.TransientModel):
    _inherit = 'res.config.settings'
    default_name = fields.Selection([
        ('python', 'python language'),
        ('java', 'java language')
        ], 'Demo Name',
        default='python',
        default_model='demo')

xml:

<?xml version="1.0" encoding="utf-8"?>
<odoo>

    <record id="res_config_settings_view_demo_form" model="ir.ui.view">
        <field name="name">res.config.demo</field>
        <field name="model">res.config.settings</field>

        <field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
        <field name="arch" type="xml">
            <xpath expr="//div[@id='languages']/div" position="inside">

                <div class="col-xs-12 col-md-6 o_setting_box">
                    <div class="o_setting_right_pane">
                        <label for="default_name"/>
                        <div class="text-muted">
                            Place choose the default name
                        </div>
                        <div class="content-group">
                            <div class="mt16">
                                <field name="default_name" class="o_light_label" widget="radio"/>
                            </div>
                        </div>
                    </div>
                </div>
            </xpath>
        </field>
    </record>
</odoo>

!注意:继承的视图来自base_setup这个模块,要在__manifest__中加载。

2、安装或者卸载模块

这种字段需要以_module 开头

用法:

  

python代码:

from odoo import models, fields, api, _

class ResConfigSettings(models.TransientModel):
    _inherit = 'res.config.settings'
    default_name = fields.Selection([
        ('python', 'python language'),
        ('java', 'java language')
        ], 'Demo Name',
        default='python',
        default_model='demo')
    module_test_controller = fields.Boolean("Demo")

3、设置系统参数

设置好了之后点击  技术-->系统参数  就能看到

 python代码:

from odoo import models, fields, api, _

class ResConfigSettings(models.TransientModel):
    _inherit = 'res.config.settings'
    default_name = fields.Selection([
        ('python', 'python language'),
        ('java', 'java language')
        ], 'Demo Name',
        default='python',
        default_model='demo')
    module_test_controller = fields.Boolean("Demo")
    demo_config_parameter = fields.Char(config_parameter='demo.config_parameter')

属性:config_parameter就是系统参数中的key

4、设置用户组

这种类型的字段以 group_开头,可以设置group属性,和 implied_group属性,group属性不设置的话默认为 base.group_user,这个字段一般设置为Boolean类型,如果值为True的话,group属性的用户组就拥有 implied_group用户组的所有权限。

from odoo import models, fields, api, _

class ResConfigSettings(models.TransientModel):
    _inherit = 'res.config.settings'
    default_name = fields.Selection([
        ('python', 'python language'),
        ('java', 'java language')
        ], 'Demo Name',
        default='python',
        default_model='demo')
    module_test_controller = fields.Boolean("Demo")
    demo_config_parameter = fields.Char(config_parameter='demo.config_parameter')
    group_demo = fields.Boolean(group='aaa',implied_group='bbb')

以上定义,如果前端勾选了的话,aaa这个组就拥有bbb这个用户组的权限。

5、源码分析

_get_classified_fields方法

目的是对res.config.settings的每一个字段进行类型和属性检查、分类

    def _get_classified_fields(self):
        # 获取模型对象
        IrModule = self.env['ir.module.module']
        Groups = self.env['res.groups']
        ref = self.env.ref

        defaults, groups, modules, configs, others = [], [], [], [], []
        # self._fields.items() res.config.settings模型的字段
        for name, field in self._fields.items():
            if name.startswith('default_'):
                # 判断 default开头的字段有没有default_模型这个属性,没有的话就报错
                if not hasattr(field, 'default_model'):
                    raise Exception("Field %s without attribute 'default_model'" % field)
                # 添加三元组
                defaults.append((name, field.default_model, name[8:]))
            # 判断以 group_开头的字段
            elif name.startswith('group_'):
                # 检查字段类型,必须为 boolean 和selection类型,必须要有implied_group 属性
                if field.type not in ('boolean', 'selection'):
                    raise Exception("Field %s must have type 'boolean' or 'selection'" % field)
                if not hasattr(field, 'implied_group'):
                    raise Exception("Field %s without attribute 'implied_group'" % field)
                # 获取字段的group属性,如果没有,默认为base.group_user
                field_group_xmlids = getattr(field, 'group', 'base.group_user').split(',')
                # 用户组字符串转化为res.groups记录集  例如: res.groups(1,)
                field_groups = Groups.concat(*(ref(it) for it in field_group_xmlids))
                # 追加三元组 分别为 字段名、用户组、继承的用户组
                groups.append((name, field_groups, ref(field.implied_group)))
            # 判断字段以 module_开头
            elif name.startswith('module_'):
                # 这种字段必须为 boolean类型和selection类型
                if field.type not in ('boolean', 'selection'):
                    raise Exception("Field %s must have type 'boolean' or 'selection'" % field)
                # 搜索模块,返回一个记录对象 以字段  module_sale_margin为例,搜索名为 sale_margin的模型
                module = IrModule.sudo().search([('name', '=', name[7:])], limit=1)
                modules.append((name, module))
            # 非 以group_、module、default、开头,而有着config_parameter属性的字段
            elif hasattr(field, 'config_parameter'):
                # 满足以下字段类型
                if field.type not in ('boolean', 'integer', 'float', 'char', 'selection', 'many2one'):
                    raise Exception("Field %s must have type 'boolean', 'integer', 'float', 'char', 'selection' or 'many2one'" % field)
                configs.append((name, field.config_parameter))
            # 以上条件都不满足
            else:
                others.append(name)

        return {'default': defaults, 'group': groups, 'module': modules, 'config': configs, 'other': others}

execute方法:

点击保存的时候调用

    def execute(self):
        self.ensure_one()
        if not self.env.is_admin():
            raise AccessError(_("Only administrators can change the settings"))
        self = self.with_context(active_test=False)
        # 获取分类之后的字段
        classified = self._get_classified_fields()
        # 主要对 default_ ,config_parameter,group_的值进行设置
        self.set_values()
        # module fields: install/uninstall the selected modules
        # 要安装的模块
        to_install = []
        # 要卸载的模块
        to_uninstall_modules = self.env['ir.module.module']
        lm = len('module_')
        for name, module in classified['module']:
            # 添加字段值为True的字段和所对应的模型
            if int(self[name]):
                to_install.append((name[lm:], module))
            else:
                # 字段的值为False,但是模型已经安装,就需要将其卸载
                if module and module.state in ('installed', 'to upgrade'):
                    to_uninstall_modules += module
        # 提交缓存
        if to_install or to_uninstall_modules:
            self.flush()

        if to_uninstall_modules:
            # 模块卸载
            to_uninstall_modules.button_immediate_uninstall()
        # 模块安装
        result = self._install_modules(to_install)
        # 卸载或者安装之后重新加载环境
        if result or to_uninstall_modules:
            # After the uninstall/install calls, the registry and environments
            # are no longer valid. So we reset the environment.
            self.env.reset()
            self = self.env()[self._name]

        # pylint: disable=next-method-called
        config = self.env['res.config'].next() or {}
        if config.get('type') not in ('ir.actions.act_window_close',):
            return config

        # force client-side reload (update user menu and current view)
        return {
            'type': 'ir.actions.client',
            'tag': 'reload',
        }

创作不易,觉得有用的小伙伴可以点个赞,也欢迎大家指正不当之处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值