diff options
| author | Xavier Morel <xmo@odoo.com> | 2018-08-21 15:20:04 +0200 |
|---|---|---|
| committer | xmo-odoo <xmo@odoo.com> | 2018-09-11 16:43:55 +0200 |
| commit | 0ecc5d50fb6bc2a8a41a0653edff4e52846acc29 (patch) | |
| tree | 247db07fd4f9607aeddee5c536e01d8dd1841aee /odoo/addons/base/models/ir_property.py | |
| parent | 7f29b31cf307e640806225440be69561f9eea0b2 (diff) | |
[IMP] base: cache property.get(res_id=False)
After installing a bunch more modules including account & some others,
company-dependent fields turn out to be horrendously inefficient (more
or less entirely unbatched): near 80% of runtime is taken by setting
those fields on the partners being created, split 28%/51% between
getting the default values (_default_company_dependent) and setting
them (_inverse_company_dependent).
clear_cache on *every* set_multi call is a bit extreme and cause test
problems (test_pickings_transfer_with_different_uom_and_back_orders
has a super fucky behaviour wrt caching so breaks when clearing the
cache on every set_multi) so only cache the "default"
case (res_id=False) and only clear when specifically setting that.
This makes fetching default values essentially disappear from the
profile.
Diffstat (limited to 'odoo/addons/base/models/ir_property.py')
| -rw-r--r-- | odoo/addons/base/models/ir_property.py | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/odoo/addons/base/models/ir_property.py b/odoo/addons/base/models/ir_property.py index 8ec49e16ea7..ad3f6586926 100644 --- a/odoo/addons/base/models/ir_property.py +++ b/odoo/addons/base/models/ir_property.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from operator import itemgetter - from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import pycompat +from odoo.tools import pycompat, ormcache TYPE2FIELD = { 'char': 'value_text', @@ -87,12 +85,43 @@ class Property(models.Model): @api.multi def write(self, values): - return super(Property, self).write(self._update_values(values)) + # if any of the records we're writing on has a res_id=False *or* + # we're writing a res_id=False on any record + default_set = False + if self._ids: + self.env.cr.execute( + 'SELECT EXISTS (SELECT 1 FROM ir_property WHERE id in %s AND res_id IS NULL)', [self._ids]) + default_set = self.env.cr.rowcount == 1 or any( + v.get('res_id') is False + for v in values + ) + r = super(Property, self).write(self._update_values(values)) + if default_set: + self.clear_caches() + return r @api.model_create_multi def create(self, vals_list): vals_list = [self._update_values(vals) for vals in vals_list] - return super(Property, self).create(vals_list) + created_default = any(not v.get('res_id') for v in vals_list) + r = super(Property, self).create(vals_list) + if created_default: + self.clear_caches() + return r + + @api.multi + def unlink(self): + default_deleted = False + if self._ids: + self.env.cr.execute( + 'SELECT EXISTS (SELECT 1 FROM ir_property WHERE id in %s)', + [self._ids] + ) + default_deleted = self.env.cr.rowcount == 1 + r = super().unlink() + if default_deleted: + self.clear_caches() + return r @api.multi def get_by_record(self): @@ -122,14 +151,39 @@ class Property(models.Model): @api.model def get(self, name, model, res_id=False): + if not res_id: + t, v = self._get_default_property(name, model) + if not v or t != 'many2one': + return v + return self.env[v[0]].browse(v[1]) + + p = self._get_property(name, model, res_id=res_id) + if p: + return p.get_by_record() + return False + + # only cache Property.get(res_id=False) as that's + # sub-optimally, we can only call _company_default_get without a field + # unless we want to create a more complete helper which does the + # returning-a-company-id-from-a-model-and-name + COMPANY_KEY = "self.env.context.get('force_company') or self.env['res.company']._company_default_get(model).id" + @ormcache(COMPANY_KEY, 'name', 'model') + def _get_default_property(self, name, model): + prop = self._get_property(name, model, res_id=False) + if not prop: + return None, False + v = prop.get_by_record() + if prop.type != 'many2one': + return prop.type, v + return 'many2one', v and (v._name, v.id) + + def _get_property(self, name, model, res_id): domain = self._get_domain(name, model) if domain is not None: domain = [('res_id', '=', res_id)] + domain #make the search with company_id asc to make sure that properties specific to a company are given first - prop = self.search(domain, limit=1, order='company_id') - if prop: - return prop.get_by_record() - return False + return self.search(domain, limit=1, order='company_id') + return self.browse(()) def _get_domain(self, prop_name, model): self._cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", (prop_name, model)) @@ -170,7 +224,6 @@ class Property(models.Model): default_value = result.pop(False, False) for id in ids: result.setdefault(id, default_value) - return result @api.model |
