一、概述
本章内容主要介绍Environment,以及model.env和request.env是如何指向Environment实例的,为下一章《odoo数据库连接层》做铺垫。
二、Environment
2.1 介绍env(官方文档摘录)
'class:`~odoo.api.Environment’存储了ORM所使用的各种上下文数据:数据库游标database cursor(用于数据库查询),当前用户user(用于访问权限检查)和当前上下文context(存储任意的元数据)。环境也存储缓存。
所有的记录集都有一个environment,这个环境是不变的,可以使用属性"odoo.models.Model.env"来使用环境变量,使用"~odoo.api.Environment.user"获取当前用户,使用"odoo.api.Environment.cr"获取游标,使用"odoo.api.Environment.context"获取上下文。
当从一个记录集创建另一个记录集时,environment会被继承。环境变量也能获取另一个model的空记录集,然后使用空的记录集查询对象的model记录。
替换environment,原本的env是不能改变的,但可以获取一个新的env进行操作或者替换当前env。使用"odoo.models.Model.sudo"方法修改当前用户,默认为超级管理员。使用"odoo.models.Model.with_context"方法替换当前environment的context,with_context可以接收一个位置参数或者通过关键字参数传递多个参数。使用"odoo.models.Model.with_env"方法替换当前env
# create partner object as administrator
env['res.partner'].sudo().create({
'name': "A Partner"})
# list partners visible by the "public" user
public = env.ref('base.public_user')
env['res.partner'].sudo(public).search([])
2.2 源码分析
Environment维护了cr、uid、context及数据集缓存
class Environment(Mapping):
""" An environment wraps data for ORM records:
- :attr:`cr`, the current database cursor;
- :attr:`uid`, the current user id;
- :attr:`context`, the current context dictionary.
It provides access to the registry by implementing a mapping from model
names to new api models. It also holds a cache for records, and a data
structure to manage recomputations.
"""
_local = Local()
@classproperty
def envs(cls):
return cls._local.environments
def __new__(cls, cr, uid, context):
# 这里实现了单例模式,当env存在实例化对象且args一致时,则返回当前的env,否则再创建一个新的env对象
assert context is not None
args = (cr, uid, context)
# if env already exists, return it
env, envs = None, cls.envs
for env in envs:
if env.args == args:
return env
# otherwise create environment, and add it in the set
self = object.__new__(cls)
self.cr, self.uid, self.context = self.args = (cr, uid, frozendict(context))
self.registry = Registry(cr.dbname)
self.cache = envs.cache
self._cache_key = (cr, uid)
self._protected = StackMap() # {field: ids, ...}
self.dirty = defaultdict(set) # {record: set(field_name), ...}
self.all = envs
envs.add(self)
return self
#
# Mapping methods
#
def __getitem__(self, model_name):
# 该方法实现了env对model_name取key,返回封装了env的model对象
""" Return an empty recordset from the given model. """
return self.registry[model_name]._browse((), self)
def ref(self, xml_id, raise_if_not_found=True):
# 通过外部id获取xml记录