[REF] models, fields: refactor fields_get
- Filter in attributes rather than filter out.
The goal is to not gather attributes which are
costly in term of performance if they are not requested
in the first place.
e.g., with all modules installed:
- Before rev:
```py
In [1]: %time for _i in range(1000): self.env["res.partner"].fields_get(attributes=['readonly', 'required', 'states', 'invisible']);self.invalidate_cache()
CPU times: user 1.99 s, sys: 9.83 ms, total: 2 s
Wall time: 2.03 s
```
- After rev:
```py
In [2]: %time for _i in range(1000): self.env["res.partner"].fields_get(attributes=['readonly', 'required', 'states', 'invisible']);self.invalidate_cache()
CPU times: user 345 ms, sys: 0 ns, total: 345 ms
Wall time: 345 ms
```
- Use the `_description_` mechanism for the attributes `name` and `type`,
so its no longer needed to treat them as exception in
`field_get` and `get_description` respectively,
and make the code shorter and cleaner.
- Move out from `fields_get` the block
```py
has_access = functools.partial(self.check_access_rights, raise_exception=False)
readonly = not (has_access('write') or has_access('create'))
...
if readonly:
description['readonly'] = True
description['states'] = {}
```
because:
- It meant you had a different behavior using `fields_get` or `get_description`
for the keys `readonly` and `states`, meaning a field could be marked as `readonly`
by `fields_get` but not by `get_description`, which is confusing.
- It is actually used in only one place, the post-process of back-end views,
which mark the fields readonly for the web client if you do not have
the create or write access to their model.
closes odoo/odoo#87273
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import ast
|
||||
import collections
|
||||
import datetime
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
@@ -2195,7 +2196,13 @@ class NameManager:
|
||||
|
||||
@lazy_property
|
||||
def field_info(self):
|
||||
return self.model.fields_get()
|
||||
field_info = self.model.fields_get()
|
||||
has_access = functools.partial(self.model.check_access_rights, raise_exception=False)
|
||||
if not (has_access('write') or has_access('create')):
|
||||
for info in field_info.vals():
|
||||
info['readonly'] = True
|
||||
info['states'] = {}
|
||||
return field_info
|
||||
|
||||
def has_field(self, name, info=frozendict()):
|
||||
self.available_fields[name].update(info)
|
||||
|
||||
+6
-2
@@ -793,10 +793,12 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
# Field description
|
||||
#
|
||||
|
||||
def get_description(self, env):
|
||||
def get_description(self, env, attributes=None):
|
||||
""" Return a dictionary that describes the field ``self``. """
|
||||
desc = {'type': self.type}
|
||||
desc = {}
|
||||
for attr, prop in self.description_attrs:
|
||||
if attributes is not None and attr not in attributes:
|
||||
continue
|
||||
value = getattr(self, prop)
|
||||
if callable(value):
|
||||
value = value(env)
|
||||
@@ -806,6 +808,8 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
return desc
|
||||
|
||||
# properties used by get_description()
|
||||
_description_name = property(attrgetter('name'))
|
||||
_description_type = property(attrgetter('type'))
|
||||
_description_store = property(attrgetter('store'))
|
||||
_description_manual = property(attrgetter('manual'))
|
||||
_description_related = property(attrgetter('related'))
|
||||
|
||||
+1
-12
@@ -3195,9 +3195,6 @@ class BaseModel(metaclass=MetaModel):
|
||||
:param allfields: list of fields to document, all if empty or not provided
|
||||
:param attributes: list of description attributes to return for each field, all if empty or not provided
|
||||
"""
|
||||
has_access = functools.partial(self.check_access_rights, raise_exception=False)
|
||||
readonly = not (has_access('write') or has_access('create'))
|
||||
|
||||
res = {}
|
||||
for fname, field in self._fields.items():
|
||||
if allfields and fname not in allfields:
|
||||
@@ -3205,15 +3202,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
if field.groups and not self.env.su and not self.user_has_groups(field.groups):
|
||||
continue
|
||||
|
||||
description = field.get_description(self.env)
|
||||
description['name'] = fname
|
||||
if readonly:
|
||||
description['readonly'] = True
|
||||
description['states'] = {}
|
||||
if attributes:
|
||||
description = {key: val
|
||||
for key, val in description.items()
|
||||
if key in attributes}
|
||||
description = field.get_description(self.env, attributes=attributes)
|
||||
res[fname] = description
|
||||
|
||||
return res
|
||||
|
||||
Reference in New Issue
Block a user