[IMP] core: search() and _search() no longer have parameter count
The parameter in search() is redundant with method search_count(), and was making the calls less readable. The method _search() is aimed at always returning a Query object. The method can therefore never return an integer, hence the removal of the parameter. This does not actually remove any functionality from the method; counting result is simply given by using it differently. Part-of: odoo/odoo#112126
This commit is contained in:
@@ -79,8 +79,11 @@ class SetupBarBankConfigWizard(models.TransientModel):
|
||||
num_journals_without_account = fields.Integer(default=lambda self: self._number_unlinked_journal())
|
||||
|
||||
def _number_unlinked_journal(self):
|
||||
return self.env['account.journal'].search([('type', '=', 'bank'), ('bank_account_id', '=', False),
|
||||
('id', '!=', self.default_linked_journal_id())], count=True)
|
||||
return self.env['account.journal'].search_count([
|
||||
('type', '=', 'bank'),
|
||||
('bank_account_id', '=', False),
|
||||
('id', '!=', self.default_linked_journal_id()),
|
||||
])
|
||||
|
||||
@api.onchange('acc_number')
|
||||
def _onchange_acc_number(self):
|
||||
|
||||
@@ -774,7 +774,7 @@ class Lead(models.Model):
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def search(self, domain, offset=0, limit=None, order=None, count=False):
|
||||
def search(self, domain, offset=0, limit=None, order=None):
|
||||
""" Override to support ordering on my_activity_date_deadline.
|
||||
|
||||
Ordering through web client calls search_read with an order parameter set.
|
||||
@@ -804,8 +804,9 @@ class Lead(models.Model):
|
||||
All other search and search_read are left untouched by this override to avoid
|
||||
side effects. Search_count is not affected by this override.
|
||||
"""
|
||||
if count or not order or 'my_activity_date_deadline' not in order:
|
||||
return super(Lead, self).search(domain, offset=offset, limit=limit, order=order, count=count)
|
||||
if not order or 'my_activity_date_deadline' not in order:
|
||||
return super().search(domain, offset, limit, order)
|
||||
|
||||
order_items = [order_item.strip().lower() for order_item in (order or self._order).split(',')]
|
||||
|
||||
# Perform a read_group on my activities to get a mapping lead_id / deadline
|
||||
@@ -825,7 +826,7 @@ class Lead(models.Model):
|
||||
|
||||
# Search leads linked to those activities and order them. See docstring
|
||||
# of this method for more details.
|
||||
search_res = super(Lead, self).search(my_lead_domain, offset=0, limit=None, order=my_lead_order, count=count)
|
||||
search_res = super().search(my_lead_domain, order=my_lead_order)
|
||||
my_lead_ids_ordered = sorted(search_res.ids, key=lambda lead_id: my_lead_mapping[lead_id], reverse=not activity_asc)
|
||||
# keep only requested window (offset + limit, or offset+)
|
||||
my_lead_ids_keep = my_lead_ids_ordered[offset:(offset + limit)] if limit else my_lead_ids_ordered[offset:]
|
||||
@@ -847,9 +848,9 @@ class Lead(models.Model):
|
||||
lead_offset = 0
|
||||
lead_order = ', '.join(item for item in order_items if 'my_activity_date_deadline' not in item)
|
||||
|
||||
other_lead_res = super(Lead, self).search(
|
||||
other_lead_res = super().search(
|
||||
expression.AND([[('id', 'not in', my_lead_ids_skip)], domain]),
|
||||
offset=lead_offset, limit=lead_limit, order=lead_order, count=count
|
||||
lead_offset, lead_limit, lead_order,
|
||||
)
|
||||
return self.browse(my_lead_ids_keep) + other_lead_res
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ class HrEmployeePrivate(models.Model):
|
||||
return self.env['hr.employee.public'].get_view(view_id, view_type, **options)
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
"""
|
||||
We override the _search because it is the method that checks the access rights
|
||||
This is correct to override the _search. That way we enforce the fact that calling
|
||||
@@ -246,14 +246,14 @@ class HrEmployeePrivate(models.Model):
|
||||
employees exactly match the ids of the related hr.employee.
|
||||
"""
|
||||
if self.check_access_rights('read', raise_exception=False):
|
||||
return super(HrEmployeePrivate, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
try:
|
||||
ids = self.env['hr.employee.public']._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
ids = self.env['hr.employee.public']._search(domain, offset, limit, order, access_rights_uid)
|
||||
except ValueError:
|
||||
raise AccessError(_('You do not have access to this document.'))
|
||||
if not count and isinstance(ids, Query):
|
||||
if isinstance(ids, Query):
|
||||
# the result is expected from this table, so we should link tables
|
||||
ids = super(HrEmployeePrivate, self.sudo())._search([('id', 'in', ids)])
|
||||
ids = super(HrEmployeePrivate, self.sudo())._search([('id', 'in', ids)], order=order)
|
||||
return ids
|
||||
|
||||
def get_formview_id(self, access_uid=None):
|
||||
|
||||
@@ -553,7 +553,7 @@ class HolidaysType(models.Model):
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override _search to order the results, according to some employee.
|
||||
The order is the following
|
||||
|
||||
@@ -566,12 +566,13 @@ class HolidaysType(models.Model):
|
||||
to the method.
|
||||
"""
|
||||
employee_id = self._get_contextual_employee_id()
|
||||
post_sort = (not count and not order and employee_id)
|
||||
leave_ids = super(HolidaysType, self)._search(args, offset=offset, limit=(None if post_sort else limit), order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
leaves = self.browse(leave_ids)
|
||||
if post_sort:
|
||||
return leaves.sorted(key=self._model_sorting_key, reverse=True).ids[:limit or None]
|
||||
return leave_ids
|
||||
if not order and employee_id:
|
||||
# retrieve all leaves, sort them, then apply offset and limit
|
||||
leaves = self.browse(super()._search(domain, access_rights_uid=access_rights_uid))
|
||||
leaves = leaves.sorted(key=self._model_sorting_key, reverse=True)
|
||||
leaves = leaves[offset:(offset + limit) if limit else None]
|
||||
return leaves.ids
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
def action_see_days_allocated(self):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -372,7 +372,7 @@ class MailActivity(models.Model):
|
||||
return super(MailActivity, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override that adds specific access rights of mail.activity, to remove
|
||||
ids uid could not see according to our custom rules. Please refer to
|
||||
_filter_access_rules_remaining for more details about those rules.
|
||||
@@ -381,16 +381,10 @@ class MailActivity(models.Model):
|
||||
|
||||
# Rules do not apply to administrator
|
||||
if self.env.is_superuser():
|
||||
return super(MailActivity, self)._search(
|
||||
args, offset=offset, limit=limit, order=order,
|
||||
count=count, access_rights_uid=access_rights_uid)
|
||||
# Perform a super with count as False, to have the ids, not a counter
|
||||
ids = super(MailActivity, self)._search(
|
||||
args, offset=offset, limit=limit, order=order,
|
||||
count=False, access_rights_uid=access_rights_uid)
|
||||
if not ids and count:
|
||||
return 0
|
||||
elif not ids:
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
ids = super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
if not ids:
|
||||
return ids
|
||||
|
||||
# check read access rights before checking the actual rules on the given ids
|
||||
@@ -426,12 +420,9 @@ class MailActivity(models.Model):
|
||||
activity['id'] for activity in activities_to_check
|
||||
if activity['res_model'] == doc_model and activity['res_id'] in valid_doc_ids)
|
||||
|
||||
if count:
|
||||
return len(allowed_ids)
|
||||
else:
|
||||
# re-construct a list based on ids, because 'allowed_ids' does not keep the original order
|
||||
id_list = [id for id in ids if id in allowed_ids]
|
||||
return id_list
|
||||
# re-construct a list based on ids, because 'allowed_ids' does not keep the original order
|
||||
id_list = [id for id in ids if id in allowed_ids]
|
||||
return id_list
|
||||
|
||||
@api.model
|
||||
def _read_group_raw(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
@@ -447,7 +438,7 @@ class MailActivity(models.Model):
|
||||
|
||||
# Rules do not apply to administrator
|
||||
if not self.env.is_superuser():
|
||||
allowed_ids = self._search(domain, count=False)
|
||||
allowed_ids = self._search(domain)
|
||||
if allowed_ids:
|
||||
domain = expression.AND([domain, [('id', 'in', allowed_ids)]])
|
||||
else:
|
||||
|
||||
@@ -51,23 +51,18 @@ class MailBlackList(models.Model):
|
||||
values['email'] = tools.email_normalize(values['email'])
|
||||
return super(MailBlackList, self).write(values)
|
||||
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override _search in order to grep search on email field and make it
|
||||
lower-case and sanitized """
|
||||
if args:
|
||||
new_args = []
|
||||
for arg in args:
|
||||
if isinstance(arg, (list, tuple)) and arg[0] == 'email' and isinstance(arg[2], str):
|
||||
normalized = tools.email_normalize(arg[2])
|
||||
if normalized:
|
||||
new_args.append([arg[0], arg[1], normalized])
|
||||
else:
|
||||
new_args.append(arg)
|
||||
else:
|
||||
new_args.append(arg)
|
||||
else:
|
||||
new_args = args
|
||||
return super(MailBlackList, self)._search(new_args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
def normalize(arg):
|
||||
if isinstance(arg, (list, tuple)) and arg[0] == 'email' and isinstance(arg[2], str):
|
||||
normalized = tools.email_normalize(arg[2])
|
||||
if normalized:
|
||||
return (arg[0], arg[1], normalized)
|
||||
return arg
|
||||
|
||||
domain = [normalize(item) for item in domain]
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
def _add(self, email, message=None):
|
||||
normalized = tools.email_normalize(email)
|
||||
|
||||
@@ -256,7 +256,7 @@ class Message(models.Model):
|
||||
self._cr.execute("""CREATE INDEX IF NOT EXISTS mail_message_model_res_id_id_idx ON mail_message (model, res_id, id)""")
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override that adds specific access rights of mail.message, to remove
|
||||
ids uid could not see according to our custom rules. Please refer to
|
||||
check_access_rule for more details about those rules.
|
||||
@@ -273,19 +273,13 @@ class Message(models.Model):
|
||||
"""
|
||||
# Rules do not apply to administrator
|
||||
if self.env.is_superuser():
|
||||
return super(Message, self)._search(
|
||||
args, offset=offset, limit=limit, order=order,
|
||||
count=count, access_rights_uid=access_rights_uid)
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
# Non-employee see only messages with a subtype and not internal
|
||||
if not self.env['res.users'].has_group('base.group_user'):
|
||||
args = expression.AND([self._get_search_domain_share(), args])
|
||||
domain = expression.AND([self._get_search_domain_share(), domain])
|
||||
# Perform a super with count as False, to have the ids, not a counter
|
||||
ids = super(Message, self)._search(
|
||||
args, offset=offset, limit=limit, order=order,
|
||||
count=False, access_rights_uid=access_rights_uid)
|
||||
if not ids and count:
|
||||
return 0
|
||||
elif not ids:
|
||||
ids = super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
if not ids:
|
||||
return ids
|
||||
|
||||
pid = self.env.user.partner_id.id
|
||||
@@ -319,12 +313,9 @@ class Message(models.Model):
|
||||
|
||||
final_ids = author_ids | partner_ids | allowed_ids
|
||||
|
||||
if count:
|
||||
return len(final_ids)
|
||||
else:
|
||||
# re-construct a list based on ids, because set did not keep the original order
|
||||
id_list = [id for id in ids if id in final_ids]
|
||||
return id_list
|
||||
# re-construct a list based on ids, because set did not keep the original order
|
||||
id_list = [id for id in ids if id in final_ids]
|
||||
return id_list
|
||||
|
||||
@api.model
|
||||
def _find_allowed_model_wise(self, doc_model, doc_dict):
|
||||
|
||||
@@ -219,7 +219,7 @@ class MrpBom(models.Model):
|
||||
def check_kit_has_not_orderpoint(self):
|
||||
product_ids = [pid for bom in self.filtered(lambda bom: bom.type == "phantom")
|
||||
for pid in (bom.product_id.ids or bom.product_tmpl_id.product_variant_ids.ids)]
|
||||
if self.env['stock.warehouse.orderpoint'].search([('product_id', 'in', product_ids)], count=True):
|
||||
if self.env['stock.warehouse.orderpoint'].search_count([('product_id', 'in', product_ids)], limit=1):
|
||||
raise ValidationError(_("You can not create a kit-type bill of materials for products that have at least one reordering rule."))
|
||||
|
||||
@api.ondelete(at_uninstall=False)
|
||||
|
||||
@@ -303,9 +303,13 @@ class Orderpoint(models.Model):
|
||||
|
||||
@api.constrains('product_id')
|
||||
def check_product_is_not_kit(self):
|
||||
if self.env['mrp.bom'].search(['|', ('product_id', 'in', self.product_id.ids),
|
||||
'&', ('product_id', '=', False), ('product_tmpl_id', 'in', self.product_id.product_tmpl_id.ids),
|
||||
('type', '=', 'phantom')], count=True):
|
||||
domain = [
|
||||
'|', ('product_id', 'in', self.product_id.ids),
|
||||
'&', ('product_id', '=', False),
|
||||
('product_tmpl_id', 'in', self.product_id.product_tmpl_id.ids),
|
||||
('type', '=', 'phantom'),
|
||||
]
|
||||
if self.env['mrp.bom'].search_count(domain, limit=1):
|
||||
raise ValidationError(_("A product with a kit-type bill of materials can not have a reordering rule."))
|
||||
|
||||
def _get_orderpoint_products(self):
|
||||
|
||||
@@ -60,23 +60,18 @@ class PhoneBlackList(models.Model):
|
||||
values['number'] = sanitized
|
||||
return super(PhoneBlackList, self).write(values)
|
||||
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override _search in order to grep search on sanitized number field """
|
||||
if args:
|
||||
new_args = []
|
||||
for arg in args:
|
||||
if isinstance(arg, (list, tuple)) and arg[0] == 'number' and isinstance(arg[2], str):
|
||||
number = arg[2]
|
||||
sanitized = phone_validation.phone_sanitize_numbers_w_record([number], self.env.user)[number]['sanitized']
|
||||
if sanitized:
|
||||
new_args.append([arg[0], arg[1], sanitized])
|
||||
else:
|
||||
new_args.append(arg)
|
||||
else:
|
||||
new_args.append(arg)
|
||||
else:
|
||||
new_args = args
|
||||
return super(PhoneBlackList, self)._search(new_args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
def sanitize_number(arg):
|
||||
if isinstance(arg, (list, tuple)) and arg[0] == 'number' and isinstance(arg[2], str):
|
||||
number = arg[2]
|
||||
sanitized = phone_validation.phone_sanitize_numbers_w_record([number], self.env.user)[number]['sanitized']
|
||||
if sanitized:
|
||||
return (arg[0], arg[1], sanitized)
|
||||
return arg
|
||||
|
||||
domain = [sanitize_number(item) for item in domain]
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
def add(self, number, message=None):
|
||||
sanitized = phone_validation.phone_sanitize_numbers_w_record([number], self.env.user)[number]['sanitized']
|
||||
|
||||
@@ -408,11 +408,11 @@ class ProductProduct(models.Model):
|
||||
return template.product_variant_id or template._create_first_product_variant()
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
# TDE FIXME: strange
|
||||
if self._context.get('search_default_categ_id'):
|
||||
args.append((('categ_id', 'child_of', self._context['search_default_categ_id'])))
|
||||
return super(ProductProduct, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
domain.append((('categ_id', 'child_of', self._context['search_default_categ_id'])))
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
@api.depends_context('display_default_code', 'seller_id')
|
||||
def _compute_display_name(self):
|
||||
|
||||
@@ -672,7 +672,7 @@ class Project(models.Model):
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
new_order, item_index, desc = [], -1, False
|
||||
for index, order_item in enumerate((order or self._order).split(',')):
|
||||
order_item_list = order_item.strip().lower().split(' ')
|
||||
@@ -681,7 +681,7 @@ class Project(models.Model):
|
||||
desc = order_item_list[-1] == 'desc'
|
||||
else:
|
||||
new_order.append(order_item)
|
||||
query = super()._search(args, offset, limit, ', '.join(new_order), count, access_rights_uid)
|
||||
query = super()._search(domain, offset, limit, ', '.join(new_order), access_rights_uid)
|
||||
if item_index != -1:
|
||||
query_order_list = query.order.split(',')
|
||||
query_order_list.insert(item_index, f"""
|
||||
@@ -1890,10 +1890,10 @@ class Task(models.Model):
|
||||
return super(Task, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
fields_list = {term[0] for term in args if isinstance(term, (tuple, list)) and term not in [expression.TRUE_LEAF, expression.FALSE_LEAF]}
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
fields_list = {term[0] for term in domain if isinstance(term, (tuple, list)) and term not in [expression.TRUE_LEAF, expression.FALSE_LEAF]}
|
||||
self._ensure_fields_are_accessible(fields_list)
|
||||
return super(Task, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
def mapped(self, func):
|
||||
# Note: This will protect the filtered method too
|
||||
|
||||
@@ -82,13 +82,13 @@ class TestActivityRights(TestActivityCommon):
|
||||
|
||||
# can _search activities if access to the document
|
||||
self.env['mail.activity'].with_user(self.user_employee)._search(
|
||||
[('id', '=', test_activity.id)], count=False)
|
||||
[('id', '=', test_activity.id)])
|
||||
|
||||
# cannot _search activities if no access to the document
|
||||
with patch.object(MailTestActivity, 'check_access_rights', autospec=True, side_effect=_employee_crash):
|
||||
with self.assertRaises(exceptions.AccessError):
|
||||
searched_activity = self.env['mail.activity'].with_user(self.user_employee)._search(
|
||||
[('id', '=', test_activity.id)], count=False)
|
||||
[('id', '=', test_activity.id)])
|
||||
|
||||
# can read_group activities if access to the document
|
||||
read_group_result = self.env['mail.activity'].with_user(self.user_employee).read_group(
|
||||
|
||||
@@ -528,23 +528,22 @@ class IrAttachment(models.Model):
|
||||
return super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
# add res_field=False in domain if not present; the arg[0] trick below
|
||||
# works for domain items and '&'/'|'/'!' operators too
|
||||
discard_binary_fields_attachments = False
|
||||
if not any(arg[0] in ('id', 'res_field') for arg in args):
|
||||
if not any(arg[0] in ('id', 'res_field') for arg in domain):
|
||||
discard_binary_fields_attachments = True
|
||||
args.insert(0, ('res_field', '=', False))
|
||||
domain = [('res_field', '=', False)] + domain
|
||||
|
||||
ids = super(IrAttachment, self)._search(args, offset=offset, limit=limit, order=order,
|
||||
count=False, access_rights_uid=access_rights_uid)
|
||||
ids = super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
if self.env.is_superuser():
|
||||
# rules do not apply for the superuser
|
||||
return len(ids) if count else ids
|
||||
return ids
|
||||
|
||||
if not ids:
|
||||
return 0 if count else []
|
||||
return []
|
||||
|
||||
# Work with a set, as list.remove() is prohibitive for large lists of documents
|
||||
# (takes 20+ seconds on a db with 100k docs during search_count()!)
|
||||
@@ -597,11 +596,12 @@ class IrAttachment(models.Model):
|
||||
# expected records to retrieve
|
||||
if len(orig_ids) == limit and len(result) < self._context.get('need', limit):
|
||||
need = self._context.get('need', limit) - len(result)
|
||||
result.extend(self.with_context(need=need)._search(args, offset=offset + len(orig_ids),
|
||||
limit=limit, order=order, count=False,
|
||||
access_rights_uid=access_rights_uid)[:limit - len(result)])
|
||||
more_ids = self.with_context(need=need)._search(
|
||||
domain, offset + len(orig_ids), limit, order, access_rights_uid,
|
||||
)
|
||||
result.extend(more_ids[:limit - len(result)])
|
||||
|
||||
return len(result) if count else list(result)
|
||||
return list(result)
|
||||
|
||||
def _read(self, fields):
|
||||
self.check('read')
|
||||
|
||||
@@ -138,8 +138,8 @@ class IrUiMenu(models.Model):
|
||||
return self.filtered(lambda menu: menu.id in visible_ids)
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
menu_ids = super(IrUiMenu, self)._search(args, offset=0, limit=None, order=order, count=False, access_rights_uid=access_rights_uid)
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
menu_ids = super()._search(domain, order=order, access_rights_uid=access_rights_uid)
|
||||
menus = self.browse(menu_ids)
|
||||
if menus:
|
||||
# menu filtering is done only on main menu tree, not other menu lists
|
||||
@@ -149,7 +149,7 @@ class IrUiMenu(models.Model):
|
||||
menus = menus[offset:]
|
||||
if limit:
|
||||
menus = menus[:limit]
|
||||
return len(menus) if count else menus.ids
|
||||
return menus.ids
|
||||
|
||||
def name_get(self):
|
||||
return [(menu.id, menu._get_full_name()) for menu in self]
|
||||
|
||||
@@ -113,19 +113,18 @@ class ResPartnerBank(models.Model):
|
||||
for acc in self]
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
pos = 0
|
||||
while pos < len(args):
|
||||
# DLE P14
|
||||
if args[pos][0] == 'acc_number':
|
||||
op = args[pos][1]
|
||||
value = args[pos][2]
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
def sanitize(arg):
|
||||
if isinstance(arg, (tuple, list)) and arg[0] == 'acc_number':
|
||||
value = arg[2]
|
||||
if not isinstance(value, str) and isinstance(value, Iterable):
|
||||
value = [sanitize_account_number(i) for i in value]
|
||||
else:
|
||||
value = sanitize_account_number(value)
|
||||
if 'like' in op:
|
||||
if 'like' in arg[1]:
|
||||
value = '%' + value + '%'
|
||||
args[pos] = ('sanitized_acc_number', op, value)
|
||||
pos += 1
|
||||
return super(ResPartnerBank, self)._search(args, offset, limit, order, count=count, access_rights_uid=access_rights_uid)
|
||||
return ('sanitized_acc_number', arg[1], value)
|
||||
return arg
|
||||
|
||||
domain = [sanitize(item) for item in domain]
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
@@ -886,15 +886,14 @@ class Partner(models.Model):
|
||||
return partner.name_get()[0]
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
""" Override search() to always show inactive children when searching via ``child_of`` operator. The ORM will
|
||||
always call search() with a simple domain of the form [('parent_id', 'in', [ids])]. """
|
||||
# a special ``domain`` is set on the ``child_ids`` o2m to bypass this logic, as it uses similar domain expressions
|
||||
if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in') \
|
||||
and args[0][2] != [False]:
|
||||
if len(domain) == 1 and len(domain[0]) == 3 and domain[0][:2] == ('parent_id', 'in') \
|
||||
and domain[0][2] != [False]:
|
||||
self = self.with_context(active_test=False)
|
||||
return super(Partner, self)._search(args, offset=offset, limit=limit, order=order,
|
||||
count=count, access_rights_uid=access_rights_uid)
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
@api.model
|
||||
@api.returns('self', lambda value: value.id)
|
||||
|
||||
@@ -188,14 +188,14 @@ class Groups(models.Model):
|
||||
return where
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
# add explicit ordering if search is sorted on full_name
|
||||
if order and order.startswith('full_name'):
|
||||
groups = super(Groups, self).search(args)
|
||||
groups = super().search(domain)
|
||||
groups = groups.sorted('full_name', reverse=order.endswith('DESC'))
|
||||
groups = groups[offset:offset+limit] if limit else groups[offset:]
|
||||
return len(groups) if count else groups.ids
|
||||
return super(Groups, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
return groups.ids
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
def copy(self, default=None):
|
||||
self.ensure_one()
|
||||
@@ -561,13 +561,12 @@ class Users(models.Model):
|
||||
return super(Users, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|
||||
|
||||
@api.model
|
||||
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
if not self.env.su and args:
|
||||
domain_fields = {term[0] for term in args if isinstance(term, (tuple, list))}
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
if not self.env.su and domain:
|
||||
domain_fields = {term[0] for term in domain if isinstance(term, (tuple, list))}
|
||||
if domain_fields.intersection(USER_PRIVATE_FIELDS):
|
||||
raise AccessError(_('Invalid search criterion'))
|
||||
return super(Users, self)._search(args, offset=offset, limit=limit, order=order, count=count,
|
||||
access_rights_uid=access_rights_uid)
|
||||
return super()._search(domain, offset, limit, order, access_rights_uid)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
|
||||
@@ -70,10 +70,10 @@ class TestAPI(SavepointCaseWithUserDemo):
|
||||
|
||||
@mute_logger('odoo.models')
|
||||
def test_04_query_count(self):
|
||||
""" Test the search method with count=True. """
|
||||
""" Test the search_count method. """
|
||||
self.cr.execute("SELECT COUNT(*) FROM res_partner WHERE active")
|
||||
count1 = self.cr.fetchone()[0]
|
||||
count2 = self.env['res.partner'].search([], count=True)
|
||||
count2 = self.env['res.partner'].search_count([])
|
||||
self.assertIsInstance(count1, int)
|
||||
self.assertIsInstance(count2, int)
|
||||
self.assertEqual(count1, count2)
|
||||
|
||||
@@ -203,7 +203,4 @@ class test_search(TransactionCase):
|
||||
{'name': 'runbot'},
|
||||
])
|
||||
self.assertEqual(len(partners) + count_partner_before, Partner.search_count([]))
|
||||
self.assertEqual(len(partners) + count_partner_before, Partner.search([], count=True))
|
||||
|
||||
self.assertEqual(3, Partner.search_count([], limit=3))
|
||||
self.assertEqual(3, Partner.search([], count=True, limit=3))
|
||||
|
||||
+11
-28
@@ -1469,15 +1469,13 @@ class BaseModel(metaclass=MetaModel):
|
||||
list to match all records.
|
||||
:param limit: maximum number of record to count (upperbound) (default: all)
|
||||
"""
|
||||
res = self.search(domain, limit=limit, count=True)
|
||||
return res if isinstance(res, int) else len(res)
|
||||
query = self._search(domain, limit=limit, order='id')
|
||||
return len(query)
|
||||
|
||||
@api.model
|
||||
@api.returns('self',
|
||||
upgrade=lambda self, value, domain, offset=0, limit=None, order=None, count=False: value if count else self.browse(value),
|
||||
downgrade=lambda self, value, domain, offset=0, limit=None, order=None, count=False: value if count else value.ids)
|
||||
def search(self, domain, offset=0, limit=None, order=None, count=False):
|
||||
""" search(domain[, offset=0][, limit=None][, order=None][, count=False])
|
||||
@api.returns('self')
|
||||
def search(self, domain, offset=0, limit=None, order=None):
|
||||
""" search(domain[, offset=0][, limit=None][, order=None])
|
||||
|
||||
Searches for records based on the ``domain``
|
||||
:ref:`search domain <reference/orm/domains>`.
|
||||
@@ -1487,12 +1485,11 @@ class BaseModel(metaclass=MetaModel):
|
||||
:param int offset: number of results to ignore (default: none)
|
||||
:param int limit: maximum number of records to return (default: all)
|
||||
:param str order: sort string
|
||||
:param bool count: if True, only counts and returns the number of matching records (default: False)
|
||||
:returns: at most ``limit`` records matching the search criteria
|
||||
:raise AccessError: if user is not allowed to access requested information
|
||||
"""
|
||||
res = self._search(domain, offset=offset, limit=limit, order=order, count=count)
|
||||
return res if count else self.browse(res)
|
||||
query = self._search(domain, offset=offset, limit=limit, order=order)
|
||||
return self.browse(query)
|
||||
|
||||
#
|
||||
# display_name, name_get, name_create, name_search
|
||||
@@ -4616,7 +4613,7 @@ class BaseModel(metaclass=MetaModel):
|
||||
self.env[model_name].flush_model(field_names)
|
||||
|
||||
@api.model
|
||||
def _search(self, domain, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
|
||||
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
||||
"""
|
||||
Private implementation of search() method, allowing specifying the uid to use for the access right check.
|
||||
This is useful for example when filling in the selection list for a drop-down and avoiding access rights errors,
|
||||
@@ -4625,37 +4622,23 @@ class BaseModel(metaclass=MetaModel):
|
||||
|
||||
:param access_rights_uid: optional user ID to use when checking access rights
|
||||
(not for ir.rules, this is only for ir.model.access)
|
||||
:return: a list of record ids or an integer (if count is True)
|
||||
:return: a collection of record ids (may be a ``Query`` object)
|
||||
"""
|
||||
model = self.with_user(access_rights_uid) if access_rights_uid else self
|
||||
model.check_access_rights('read')
|
||||
|
||||
if expression.is_false(self, domain):
|
||||
# optimization: no need to query, as no record satisfies the domain
|
||||
return 0 if count else []
|
||||
return ()
|
||||
|
||||
# the flush must be done before the _where_calc(), as the latter can do some selects
|
||||
self._flush_search(domain, order=order)
|
||||
|
||||
query = self._where_calc(domain)
|
||||
self._apply_ir_rules(query, 'read')
|
||||
query.limit = limit
|
||||
|
||||
if count:
|
||||
# Ignore order and offset when just counting, they don't make sense and could
|
||||
# hurt performance
|
||||
if limit:
|
||||
# Special case to avoid counting every record in DB (which can be really slow).
|
||||
# The result will be between 0 and limit.
|
||||
query_str, params = query.select("") # generates a `SELECT FROM` (faster)
|
||||
query_str = f"SELECT COUNT(*) FROM ({query_str}) t"
|
||||
else:
|
||||
query_str, params = query.select("COUNT(*)")
|
||||
|
||||
self._cr.execute(query_str, params)
|
||||
return self._cr.fetchone()[0]
|
||||
|
||||
query.order = self._generate_order_by(order, query).replace('ORDER BY ', '')
|
||||
query.limit = limit
|
||||
query.offset = offset
|
||||
|
||||
return query
|
||||
|
||||
@@ -223,6 +223,22 @@ class Query(object):
|
||||
return bool(self.get_result_ids())
|
||||
|
||||
def __len__(self):
|
||||
if self._ids is None and not self.offset:
|
||||
from_clause, where_clause, params = self.get_sql()
|
||||
where_clause = where_clause or 'TRUE'
|
||||
if self.limit:
|
||||
# apply the limit, and wrap the query into a more efficient one
|
||||
query_str = f'''
|
||||
SELECT COUNT(*) FROM (
|
||||
SELECT FROM {from_clause}
|
||||
WHERE {where_clause}
|
||||
LIMIT {int(self.limit)}
|
||||
) t
|
||||
'''
|
||||
else:
|
||||
query_str = f'SELECT COUNT(*) FROM {from_clause} WHERE {where_clause}'
|
||||
self._cr.execute(query_str, params)
|
||||
return self._cr.fetchone()[0]
|
||||
return len(self.get_result_ids())
|
||||
|
||||
def __iter__(self):
|
||||
|
||||
Reference in New Issue
Block a user