odoo17核心概念——env

env在odoo中是一个非常重要的概念,它是一个全局变量,保存了odoo运行环境的重要信息,env分为前端和后端

一、环境(env)

1、前端的env

在web\static\src\env.js中定义,包含两个重要的对象:

  • 全局数据总线bus, 可以在不同的组件之间进行通信
  • 所有的服务services

这个文件非常重要,它定义了两个函数

makeEnv: 初始化env对象。

export function makeEnv() {
    return {
        bus: new EventBus(),
        services: {},
        debug: odoo.debug,
        get isSmall() {
            throw new Error("UI service not initialized!");
        },
    };
}

startServices: 启动所有的Service, 这个函数的实现非常巧妙,因为它要在不考虑服务加载顺序的前提下解决服务之间的依赖问题。 其中细节,值得一读。

不过这里只有这两个函数的定义,并没有执行这两个函数, 真正执行这两个函数的位置在 start.js中

const env = makeEnv();
await startServices(env);

服务启动完后, 会放入env的services对象中。 注意其中放的不是服务对象本身,而是start函数的返回值。

2、 后端的env

后端的env在odoo\api.py中定义

"""The Odoo API module defines Odoo Environments and method decorators.

.. todo:: Document this module
"""

__all__ = [
    'Environment',
    'Meta',
    'model',
    'constrains', 'depends', 'onchange', 'returns',
    'call_kw',
]

文件的注释中说明了两点:
1、这个文件定义了odoo环境和方法装饰器
2、todo: 要为这个模块写文档(啥时候写?)
默认导出的对象,odoo后端最重要的一些对象
‘Environment’,
‘Meta’,
‘model’,
‘constrains’, ‘depends’, ‘onchange’, ‘returns’,
‘call_kw’,

from collections.abc import Mapping

class Environment(Mapping):
    """ The environment stores various contextual data used by the ORM:

    - :attr:`cr`: the current database cursor (for database queries);
    - :attr:`uid`: the current user id (for access rights checks);
    - :attr:`context`: the current context dictionary (arbitrary metadata);
    - :attr:`su`: whether in superuser mode.

    It provides access to the registry by implementing a mapping from model
    names to models. It also holds a cache for records, and a data
    structure to manage recomputations.
    """
    def reset(self):
        """ Reset the transaction, see :meth:`Transaction.reset`. """
        self.transaction.reset()

    def __new__(cls, cr, uid, context, su=False):
        if uid == SUPERUSER_ID:
            su = True
        assert context is not None
        args = (cr, uid, context, su)

        # determine transaction object
        transaction = cr.transaction
        if transaction is None:
            transaction = cr.transaction = Transaction(Registry(cr.dbname))

        # if env already exists, return it
        for env in transaction.envs:
            if env.args == args:
                return env

        # otherwise create environment, and add it in the set
        self = object.__new__(cls)
        args = (cr, uid, frozendict(context), su)
        self.cr, self.uid, self.context, self.su = self.args = args

        self.transaction = self.all = transaction
        self.registry = transaction.registry
        self.cache = transaction.cache
        self._cache_key = {}                    # memo {field: cache_key}
        self._protected = transaction.protected
        transaction.envs.add(self)
        return self

env对象存储了不同类型的上下文数据被ORM使用,
- :attr:cr: the current database cursor (for database queries);
- :attr:uid: the current user id (for access rights checks);
- :attr:context: the current context dictionary (arbitrary metadata);
- :attr:su: whether in superuser mode.

env继承自 collection 的Mapping

在文件的末尾有两句import有点意思

# keep those imports here in order to handle cyclic dependencies correctly
from odoo import SUPERUSER_ID
from odoo.modules.registry import Registry

之所以放在文件末尾,是为了正确的处理循环依赖。 姑且先不管的原理是啥了,不过这里引入了一个重要的对象 Regisitry ——后端的注册表

class Registry(Mapping):
    """ Model registry for a particular database.

    The registry is essentially a mapping between model names and model classes.
    There is one registry instance per database.

    """
    _lock = threading.RLock()
    _saved_lock = None

    @lazy_classproperty
    def registries(cls):
        """ A mapping from database names to registries. """
        size = config.get('registry_lru_size', None)
        if not size:
            # Size the LRU depending of the memory limits
            if os.name != 'posix':
                # cannot specify the memory limit soft on windows...
                size = 42
            else:
                # A registry takes 10MB of memory on average, so we reserve
                # 10Mb (registry) + 5Mb (working memory) per registry
                avgsz = 15 * 1024 * 1024
                size = int(config['limit_memory_soft'] / avgsz)
        return LRU(size)

    def __new__(cls, db_name):
        """ Return the registry for the given database name."""
        with cls._lock:
            try:
                return cls.registries[db_name]
            except KeyError:
                return cls.new(db_name)
            finally:
                # set db tracker - cleaned up at the WSGI dispatching phase in
                # odoo.http.root
                threading.current_thread().dbname = db_name

这里不想写的过于深入,先摸清系统的大概框架,在需要的时候再去扣细节,这才是学习的正确方法 。

你可能感兴趣的:(odoo17,odoo,odoo17)