Assuming that `field.cache_key(record)` is independent from `record.id`,
compute the cache key once for all records, and avoid using `browse` on all
record ids. This makes `get_records` about 20 times faster.
This has a good performance impact on `field.modified_draft()`, which is used
during onchanges for invalidating fields.
Suppose we convert a x2many field `foo_ids` with a many2one sub-field `bar_id`.
The conversion of the values of `bar_id` generates pairs `(id, name)`. Before
this patch, the method `name_get` is invoked on every value, one by one.
Rewrite the code to ensure that `name_get()` is invoked on all values at once.
backport of afef71d6b9
Original commit message:
Let `create` and `write` round monetary field values before sending them to the
database. Pass the values to be written to `field.convert_to_column`, so that
the currency can be retrieved from the values, and the value be rounded.
With this commit, we change the behaviour of the web client with respect
to spaces in char fields. Most of the time, starting and ending spaces
have no value, and worse, make the data not so reliable.
After this commit, field char will trim by default (so, if the user input a
char as ' abc ', the string 'abc' will be sent to the server instead).
Note that this only applies when the value of the field is changed. If
someone open a form view, then switches to edit mode and save, nothing
will change.
This is the desired behavior most of the time. However, in some rare
cases, this is actually harmful. For example, if we trim the
'decimal_point' field, it will not be possible to enter a whitespace as
decimal separator. In those cases, we introduce a new attribute 'trim',
which allow the developer to desactivate that feature.
Prefetching is underused when all fields are traversed one record at a time.
So instead, traverse all records one field at a time. This guarantees batch
prefetching/computation on every field being accessed.
That function is called when computing related fields in onchange mode.
The new implementation makes a direct access to the cache's implementation.
opw-772303
When reading a one2many field, the inverse field of the retrieved lines may
already be assigned in cache to a new record. This can happen during an
onchange. In that case, the algorithm crashes. Let's clean it up!
The command does not need to remove existing relations, as there is no relation
yet on new records. This saves one query per many2many field with that command
in a `create`.
An update by a list of commands is now guaranteed to have at most three SQL
queries to update the relation, whatever the number of commands and records.
The record cache is indexed by `(field, record_id, key)`, where `key` depends
on the environment. The key is either `(cr, uid, context)` or `(cr, uid)`,
depending on whether the field's value is context-dependent. As most fields
are not context-dependent, this should avoid some cache prefetching when
swiching context.
Make `RecordCache` work on a single record only, and implement a mapping from
field names (only) to values.
Also add explicit methods on `RecordCache` to wrap special behavior in cache,
and simplify all special values as a wrapper for a getter function.
The record cache may contain regular and special values. Modify `RecordCache`
so that only methods ending with `_value` check for regular values. The
dictionary methods considers both regular and special values as equivalent.
name in record._cache # test if cache has a value
iter(record._cache) # iterate on values
record._cache[name] # get value
record._cache.get(name) # get value or default
record._cache.has_value(name) # test if cache has a regular value
record._cache.get_value(name) # get regular value or default
The x2many "create" command is now like: `(0, ref, vals)`, where `ref` is an
arbitrary reference that may be used to identify a new line in the relation.
The reference is returned in a similar command by the method `onchange`.
`onchange` now supports self-modifying x2many fields.
Now that we're closer to switching to P3 for good, these helpers have
outlived their usefulness, and mostly add noise.
All remaining dict.iter*() or dict.view*() must be converted to the
normal keys(), values() or items() calls.
Whenever the result is likely to be used for more than the scope of a
loop, or when the dict needs to be modified during iteration, the calls
must be wrapped in a ``list()``, to protect the new P3 semantics.
Those cases are very exceptional.
Also removed some dead code or improved the API to remove unnecessary
conversions.
* unichr -> pycompat (builtin removed from Python 3, ``chr`` has
become unicode-aware)
* Psycopg2 bytea values (binary fields) are returned as memoryviews in
P3 but buffers in P2
* Both bytes and (text) strings are conventionally iterable in
P3 (they have a __iter__ method), so fix up the exclusion pattern
for flatten
* remove references to basestring & unicode (use relevant pycompat
helpers)
* remove some str calls (either entirely or replaced by relevant
helper, either text or native)
* use better API to avoid unnecessary conversions
* remove some XML declarations in views
* StringIO removed from stdlib, replace with io
* try to correctly handle BytesIO/StringIO (one is for bytes the other
is for text)
* fix base64: Python 3 removed bytes-encoding and bytes-bytes
codecs (via #encode) so replace all calls to str.encode('base64'),
also b64encode is a bytes->bytes conversion so attempt to properly
handle that
issue #8530
When deciding to prefetch records (getting records from the cache with
no value for the field being fetched), if the field was computed
`determine_value` would just get all records, not limited by the normal
prefetch limit; for large recordsets this would generate gigantic
prefetch lists for records we may not need at all.
Fix by applying the `PREFETCH_MAX` limit to records from the cache as is
done in `_prefetch_field`.
Complementarily, when traversing related fields the prefetch
environment would be lost and every record would get an empty prefetch
environment, so the values would ultimately be read one by one.
Example: select (search) 1000 product.product records, access a
related field (e.g. categ_id) in a loop, on the first iteration the
system would first read 1000 templates, then it would read each
categ_id individually, resulting in >1000 SQL queries rather than the
~2 we would expect.
Fixes#18511
When several fields are modified and trigger the same recomputations, the same
SQL queries were made to determine the records to recompute, because each field
was processed independently. In order to avoid duplicated SQL queries, process
the triggers of the modified fields altogether.
This reduces the number of queries by 15% to 25%, depending on the number of
computed fields.
Python 3's hash randomisation means columns can be iterated — and thus
initialised — in any order (within a given model/override anyway),
which means there can be an implicit dependency on column
initialisation order e.g. (res.company).currency_id has a default
which fetches the currency_id of the company_id of the administrator,
and res.company has a _order=sequence,name, if the currency_id field
is created before the sequence the SELECT query will blow up as the
sequence column will not exist yet.
Attempt to always manipulate (iterate & initialize) fields based on
their order of definition using a global sequence number.
Let `create` and `write` round monetary field values before sending them to the
database. Pass the values to be written to `field.convert_to_column`, so that
the currency can be retrieved from the values, and the value be rounded.