When you want to do batch update data. A problem was found. direct
self.env[''].write({}) is invalid. . Query data found:
model.create() records.write(). . In this case. As a developer. I must figure out this relationship
1. Find out where the model is
Because odoo loads the model dynamically. So first find out what type of current model is
Just find a model. Operable place
print(self.__class__)
<class'odoo.api.zhy.sale'>. . As can be seen. All are dynamically loaded into the odoo.api module
Second, how to distinguish between record and model
Debugging can be seen
Then for order in self:
. . As can be seen. It must have rewritten some magic functions of the model
def __str__(self):
return "%s%s" % (self._name, getattr(self, '_ids', ""))
As can be seen. The _ids attribute is the key to record and model
3. What the hell is self.env["**"]
class Environment(Mapping):
class Environment(Mapping):
def __new__(cls, cr, uid, context):
assert context is not None
args = (cr, uid, context)
# if env already exists, return it 这句就是全局envs
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
def __getitem__(self, model_name):
""" Return an empty recordset from the given model. """
return self.registry[model_name]._browse((), self)
First, the cls.envs global variable saves all env
Then rewrite []. self.env[''] is equivalent to getting the registered model and then _browse an empty record() ( empty reocord can be understood as mode l, which initializes some other parameters)
So self.env[''] gets an empty record(model)
self.registry[model_name] is the model without _browse
Four, what is _browse
@classmethod
def _browse(cls, ids, env, prefetch=None, add_prefetch=True):
""" Create a recordset instance.
:param ids: a tuple of record ids
:param env: an environment
:param prefetch: an optional prefetch object
"""
records = object.__new__(cls)
records.env = env
records._ids = ids
if prefetch is None:
prefetch = defaultdict(set) # {model_name: set(ids)}
records._prefetch = prefetch
if add_prefetch:
prefetch[cls._name].update(ids)
return records
As can be seen. Is to generate a model, and then assign the passed id
The advantage of this is that the real record will only be generated when traversing (determining the need for record). To use. The others are represented by a record(_ids). Reduce a lot of memory space
Specifically how to write ids. Please see the second analysis
5. Why doesn't self.env[''].write(()) take effect
Include self.env[""] which is model. Why does wirte not take effect
Look at the write code
@api.multi
def write(self, vals):
# 所以这里只能是记录
if not self:
return True
You can see it here. The model must have rewritten the _bool_ magic function,
def __bool__(self):
""" Test whether ``self`` is nonempty. """
return bool(getattr(self, '_ids', True))
can be seen. The true and flase of model are determined based on _ids.
self.registry[model_name]._browse((), self)
_ids=()
So the _ids attribute of self.env[""] is {}.
Can't batch wirte