[IMP] various: optimize _name_search

In the overrides of _name_search we should avoid creating domains with
huge lists of ids as it is inefficient.
We can also make sure that we optimize the empty search as in this case
the custom domain doesn't make sense, we can simply search on an empty
domain and, thanks to the limit argument, still keep a fast query.

Linked to task 1918906

Thanks to @odony and @nseinlet

closes odoo/odoo#30155

closes odoo/odoo#30887
This commit is contained in:
RomainLibert
2019-02-06 13:26:33 +00:00
committed by Yannick Tivisse
parent c0ffeeb417
commit 5fcf891e07
9 changed files with 63 additions and 42 deletions
+19 -13
View File
@@ -201,7 +201,7 @@ class AccountAccount(models.Model):
domain = ['|', ('code', '=ilike', name.split(' ')[0] + '%'), ('name', operator, name)]
if operator in expression.NEGATIVE_TERM_OPERATORS:
domain = ['&', '!'] + domain[1:]
account_ids = self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
account_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(account_ids).name_get()
@api.onchange('internal_type')
@@ -382,11 +382,13 @@ class AccountGroup(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if not args:
args = []
criteria_operator = ['|'] if operator not in expression.NEGATIVE_TERM_OPERATORS else ['&', '!']
domain = criteria_operator + [('code_prefix', '=ilike', name + '%'), ('name', operator, name)]
group_ids = self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
args = args or []
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
criteria_operator = ['|'] if operator not in expression.NEGATIVE_TERM_OPERATORS else ['&', '!']
domain = criteria_operator + [('code_prefix', '=ilike', name + '%'), ('name', operator, name)]
group_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(group_ids).name_get()
@@ -810,10 +812,13 @@ class AccountJournal(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
args = args or []
connector = '|'
if operator in expression.NEGATIVE_TERM_OPERATORS:
connector = '&'
journal_ids = self._search([connector, ('code', operator, name), ('name', operator, name)] + args, limit=limit, access_rights_uid=name_get_uid)
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
connector = '&' if operator in expression.NEGATIVE_TERM_OPERATORS else '|'
domain = [connector, ('code', operator, name), ('name', operator, name)]
journal_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(journal_ids).name_get()
@api.multi
@@ -954,10 +959,11 @@ class AccountTax(models.Model):
result format: {[(id, name), (id, name), ...]}
"""
args = args or []
if operator in expression.NEGATIVE_TERM_OPERATORS:
domain = [('description', operator, name), ('name', operator, name)]
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
domain = ['|', ('description', operator, name), ('name', operator, name)]
connector = '&' if operator in expression.NEGATIVE_TERM_OPERATORS else '|'
domain = [connector, ('description', operator, name), ('name', operator, name)]
tax_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(tax_ids).name_get()
+5 -5
View File
@@ -157,11 +157,11 @@ class AccountAnalyticAccount(models.Model):
if operator not in ('ilike', 'like', '=', '=like', '=ilike'):
return super(AccountAnalyticAccount, self)._name_search(name, args, operator, limit, name_get_uid=name_get_uid)
args = args or []
domain = ['|', ('code', operator, name), ('name', operator, name)]
partners_ids = self.env['res.partner']._search([('name', operator, name)], access_rights_uid=name_get_uid)
if partners_ids:
domain = ['|'] + domain + [('partner_id', 'in', partners_ids)]
analytic_account_ids = self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
domain = ['|', '|', ('code', operator, name), ('name', operator, name), ('partner_id.name', operator, name)]
analytic_account_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(analytic_account_ids).name_get()
+2 -1
View File
@@ -5,6 +5,7 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.osv import expression
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.float_utils import float_compare
from odoo.exceptions import UserError, AccessError
@@ -136,7 +137,7 @@ class PurchaseOrder(models.Model):
domain = []
if name:
domain = ['|', ('name', operator, name), ('partner_ref', operator, name)]
purchase_order_ids = self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
purchase_order_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(purchase_order_ids).name_get()
@api.multi
+3 -1
View File
@@ -439,7 +439,9 @@ class SaleOrder(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('sale_show_partner_name'):
if operator in ('ilike', 'like', '=', '=like', '=ilike'):
if operator == 'ilike' and not (name or '').strip():
domain = []
elif operator in ('ilike', 'like', '=', '=like', '=ilike'):
domain = expression.AND([
args or [],
['|', ('name', operator, name), ('partner_id.name', operator, name)]
+7 -3
View File
@@ -6,6 +6,7 @@ from dateutil import relativedelta
from odoo.exceptions import UserError
from odoo import api, fields, models, _
from odoo.osv import expression
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
@@ -114,9 +115,12 @@ class Location(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
""" search full name and barcode """
if args is None:
args = []
location_ids = self._search(['|', ('barcode', operator, name), ('complete_name', operator, name)] + args, limit=limit, access_rights_uid=name_get_uid)
args = args or []
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
domain = ['|', ('barcode', operator, name), ('complete_name', operator, name)]
location_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(location_ids).name_get()
def get_putaway_strategy(self, product):
+2 -1
View File
@@ -8,6 +8,7 @@ from datetime import date
from itertools import groupby
from odoo import api, fields, models, _
from odoo.osv import expression
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.float_utils import float_compare, float_is_zero, float_round
from odoo.exceptions import UserError
@@ -121,7 +122,7 @@ class PickingType(models.Model):
domain = []
if name:
domain = ['|', ('name', operator, name), ('warehouse_id.name', operator, name)]
picking_ids = self._search(domain + args, limit=limit, access_rights_uid=name_get_uid)
picking_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(picking_ids).name_get()
@api.onchange('code')
+3 -3
View File
@@ -4,6 +4,7 @@
import odoo
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import MissingError, UserError, ValidationError, AccessError
from odoo.osv import expression
from odoo.tools.safe_eval import safe_eval, test_python_expr
from odoo.tools import pycompat, wrap_module
from odoo.http import request
@@ -707,10 +708,9 @@ class IrActionsTodo(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if args is None:
args = []
args = args or []
if name:
action_ids = self._search([('action_id', operator, name)] + args, limit=limit, access_rights_uid=name_get_uid)
action_ids = self._search(expression.AND([[('action_id', operator, name)], args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(action_ids).name_get()
return super(IrActionsTodo, self)._name_search(name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
+15 -9
View File
@@ -4,6 +4,7 @@
import re
import logging
from odoo import api, fields, models
from odoo.osv import expression
from psycopg2 import IntegrityError
from odoo.tools.translate import _
_logger = logging.getLogger(__name__)
@@ -119,15 +120,20 @@ class CountryState(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if args is None:
args = []
if self.env.context.get('country_id'):
args = args + [('country_id', '=', self.env.context.get('country_id'))]
first_state_ids = self._search([('code', '=ilike', name)] + args, limit=limit, access_rights_uid=name_get_uid)
search_domain = [('name', operator, name)]
search_domain.append(('id', 'not in', first_state_ids))
state_ids = first_state_ids + self._search(search_domain + args, limit=limit, access_rights_uid=name_get_uid)
return [(state.id, state.display_name) for state in self.browse(state_ids)]
args = args or []
if 'country_id' in self.env.context:
args = expression.AND([args, [('country_id', '=', self.env.context.get('country_id'))]])
if operator == 'ilike' and not (name or '').strip():
first_domain = []
domain = []
else:
first_domain = [('code', '=ilike', name)]
domain = [('name', operator, name)]
first_state_ids = self._search(expression.AND([first_domain, args]), limit=limit, access_rights_uid=name_get_uid) if first_domain else []
state_ids = first_state_ids + [state_id for state_id in self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) if not state_id in first_state_ids]
return self.browse(state_ids).name_get()
@api.multi
def name_get(self):
+7 -6
View File
@@ -489,13 +489,14 @@ class Users(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if args is None:
args = []
user_ids = []
if name and operator in ['=', 'ilike']:
user_ids = self._search([('login', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid)
args = args or []
if operator == 'ilike' and not (name or '').strip():
domain = []
else:
domain = [('login', '=', name)]
user_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)
if not user_ids:
user_ids = self._search([('name', operator, name)] + args, limit=limit, access_rights_uid=name_get_uid)
user_ids = self._search(expression.AND([[('name', operator, name)], args]), limit=limit, access_rights_uid=name_get_uid)
return self.browse(user_ids).name_get()
@api.multi