def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_length=10, filters=None, filter_fields=None, as_dict=False, reference_doctype=None, ignore_user_permissions=False): if isinstance(filters, string_types): filters = json.loads(filters) if searchfield: sanitize_searchfield(searchfield) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower() != "select": # by method frappe.response["values"] = frappe.call(query, doctype, txt, searchfield, start, page_length, filters, as_dict=as_dict) elif not query and doctype in standard_queries: # from standard queries search_widget(doctype, txt, standard_queries[doctype][0], searchfield, start, page_length, filters) else: meta = frappe.get_meta(doctype) if query: frappe.throw(_("This query style is discontinued")) # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters == None: filters = [] or_filters = [] # build from doctype if txt: search_fields = ["name"] if meta.title_field: search_fields.append(meta.title_field) if meta.search_fields: search_fields.extend(meta.get_search_fields()) for f in search_fields: fmeta = meta.get_field(f.strip()) if (doctype not in UNTRANSLATED_DOCTYPES) and ( f == "name" or (fmeta and fmeta.fieldtype in [ "Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor" ])): or_filters.append( [doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", { "fieldname": "enabled", "fieldtype": "Check" }): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", { "fieldname": "disabled", "fieldtype": "Check" }): filters.append([doctype, "disabled", "!=", 1]) # format a list of fields combining search fields and filter fields fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) formatted_fields = [ '`tab%s`.`%s`' % (meta.name, f.strip()) for f in fields ] # find relevance as location of search term from the beginning of string `name`. used for sorting results. formatted_fields.append( """locate({_txt}, `tab{doctype}`.`name`) as `_relevance`""". format(_txt=frappe.db.escape((txt or "").replace("%", "")), doctype=doctype)) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) # 2 is the index of _relevance column order_by = "2 , {0}, `tab{1}`.idx desc".format( order_by_based_on_meta, doctype) ignore_permissions = True if doctype == "DocType" else ( cint(ignore_user_permissions) and has_permission(doctype)) if doctype in UNTRANSLATED_DOCTYPES: page_length = None values = frappe.get_list(doctype, filters=filters, fields=formatted_fields, or_filters=or_filters, limit_start=start, limit_page_length=page_length, order_by=order_by, ignore_permissions=ignore_permissions, reference_doctype=reference_doctype, as_list=not as_dict) if doctype in UNTRANSLATED_DOCTYPES: values = tuple([ v for v in list(values) if re.search(txt + ".*", ( _(v.name) if as_dict else _(v[0])), re.IGNORECASE) ]) # remove _relevance from results if as_dict: for r in values: r.pop("_relevance") frappe.response["values"] = values else: frappe.response["values"] = [r[:-1] for r in values]
def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_len=10, filters=None, filter_fields=None, as_dict=False): if isinstance(filters, basestring): import json filters = json.loads(filters) meta = frappe.get_meta(doctype) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower() != "select": # by method frappe.response["values"] = frappe.call(query, doctype, txt, searchfield, start, page_len, filters, as_dict=as_dict) elif not query and doctype in standard_queries: # from standard queries search_widget(doctype, txt, standard_queries[doctype][0], searchfield, start, page_len, filters) else: if query: frappe.throw("This query style is discontinued") # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters == None: filters = [] or_filters = [] # build from doctype if txt: search_fields = ["name"] if meta.title_field: search_fields.append(meta.title_field) if meta.search_fields: search_fields.extend(meta.get_search_fields()) for f in search_fields: fmeta = meta.get_field(f.strip()) if f == "name" or (fmeta and fmeta.fieldtype in [ "Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor" ]): or_filters.append( [doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", { "fieldname": "enabled", "fieldtype": "Check" }): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", { "fieldname": "disabled", "fieldtype": "Check" }): filters.append([doctype, "disabled", "!=", 1]) # format a list of fields combining search fields and filter fields fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) formatted_fields = [ '`tab%s`.`%s`' % (meta.name, f.strip()) for f in fields ] # find relevance as location of search term from the beginning of string `name`. used for sorting results. formatted_fields.append( """locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""". format(_txt=frappe.db.escape((txt or "").replace("%", "")), doctype=frappe.db.escape(doctype))) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) order_by = "if(_relevance, _relevance, 99999), idx desc, {0}".format( order_by_based_on_meta) values = frappe.get_list( doctype, filters=filters, fields=formatted_fields, or_filters=or_filters, limit_start=start, limit_page_length=page_len, order_by=order_by, ignore_permissions=True if doctype == "DocType" else False, # for dynamic links as_list=not as_dict) # remove _relevance from results frappe.response["fields"] = fields frappe.response["values"] = [r[:-1] for r in values]
def search_widget( doctype, txt, query=None, searchfield=None, start=0, page_length=20, filters=None, filter_fields=None, as_dict=False, reference_doctype=None, ignore_user_permissions=False, ): start = cint(start) if isinstance(filters, string_types): filters = json.loads(filters) if searchfield: sanitize_searchfield(searchfield) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower() != "select": # by method try: is_whitelisted(frappe.get_attr(query)) frappe.response["values"] = frappe.call( query, doctype, txt, searchfield, start, page_length, filters, as_dict=as_dict ) except frappe.exceptions.PermissionError as e: if frappe.local.conf.developer_mode: raise e else: frappe.respond_as_web_page( title="Invalid Method", html="Method not found", indicator_color="red", http_status_code=404 ) return except Exception as e: raise e elif not query and doctype in standard_queries: # from standard queries search_widget( doctype, txt, standard_queries[doctype][0], searchfield, start, page_length, filters ) else: meta = frappe.get_meta(doctype) if query: frappe.throw(_("This query style is discontinued")) # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters == None: filters = [] or_filters = [] translated_search_doctypes = frappe.get_hooks("translated_search_doctypes") # build from doctype if txt: search_fields = ["name"] if meta.title_field: search_fields.append(meta.title_field) if meta.search_fields: search_fields.extend(meta.get_search_fields()) for f in search_fields: fmeta = meta.get_field(f.strip()) if (doctype not in translated_search_doctypes) and ( f == "name" or ( fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor"] ) ): or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", {"fieldname": "enabled", "fieldtype": "Check"}): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", {"fieldname": "disabled", "fieldtype": "Check"}): filters.append([doctype, "disabled", "!=", 1]) # format a list of fields combining search fields and filter fields fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) formatted_fields = ["`tab%s`.`%s`" % (meta.name, f.strip()) for f in fields] # find relevance as location of search term from the beginning of string `name`. used for sorting results. formatted_fields.append( """locate({_txt}, `tab{doctype}`.`name`) as `_relevance`""".format( _txt=frappe.db.escape((txt or "").replace("%", "").replace("@", "")), doctype=doctype ) ) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) # 2 is the index of _relevance column order_by = "_relevance, {0}, `tab{1}`.idx desc".format(order_by_based_on_meta, doctype) ptype = "select" if frappe.only_has_select_perm(doctype) else "read" ignore_permissions = ( True if doctype == "DocType" else (cint(ignore_user_permissions) and has_permission(doctype, ptype=ptype)) ) if doctype in translated_search_doctypes: page_length = None values = frappe.get_list( doctype, filters=filters, fields=formatted_fields, or_filters=or_filters, limit_start=start, limit_page_length=page_length, order_by=order_by, ignore_permissions=ignore_permissions, reference_doctype=reference_doctype, as_list=not as_dict, strict=False, ) if doctype in translated_search_doctypes: # Filtering the values array so that query is included in very element values = ( v for v in values if re.search(f"{re.escape(txt)}.*", _(v.name if as_dict else v[0]), re.IGNORECASE) ) # Sorting the values array so that relevant results always come first # This will first bring elements on top in which query is a prefix of element # Then it will bring the rest of the elements and sort them in lexicographical order values = sorted(values, key=lambda x: relevance_sorter(x, txt, as_dict)) # remove _relevance from results if as_dict: for r in values: r.pop("_relevance") frappe.response["values"] = values else: frappe.response["values"] = [r[:-1] for r in values]
def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_length=10, filters=None, filter_fields=None, as_dict=False, reference_doctype=None, ignore_user_permissions=False): if isinstance(filters, string_types): filters = json.loads(filters) if searchfield: sanitize_searchfield(searchfield) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower()!="select": # by method frappe.response["values"] = frappe.call(query, doctype, txt, searchfield, start, page_length, filters, as_dict=as_dict) elif not query and doctype in standard_queries: # from standard queries search_widget(doctype, txt, standard_queries[doctype][0], searchfield, start, page_length, filters) else: meta = frappe.get_meta(doctype) if query: frappe.throw(_("This query style is discontinued")) # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters==None: filters = [] or_filters = [] # build from doctype if txt: search_fields = ["name"] if meta.title_field: search_fields.append(meta.title_field) if meta.search_fields: search_fields.extend(meta.get_search_fields()) for f in search_fields: fmeta = meta.get_field(f.strip()) if (doctype not in UNTRANSLATED_DOCTYPES) and (f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor"])): or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", {"fieldname":"enabled", "fieldtype":"Check"}): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", {"fieldname":"disabled", "fieldtype":"Check"}): filters.append([doctype, "disabled", "!=", 1]) # format a list of fields combining search fields and filter fields fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) formatted_fields = ['`tab%s`.`%s`' % (meta.name, f.strip()) for f in fields] # find relevance as location of search term from the beginning of string `name`. used for sorting results. formatted_fields.append("""locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""".format( _txt=frappe.db.escape((txt or "").replace("%", "")), doctype=frappe.db.escape(doctype))) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) order_by = "if(_relevance, _relevance, 99999), {0}, `tab{1}`.idx desc".format(order_by_based_on_meta, doctype) ignore_permissions = True if doctype == "DocType" else (cint(ignore_user_permissions) and has_permission(doctype)) if doctype in UNTRANSLATED_DOCTYPES: page_length = None values = frappe.get_list(doctype, filters=filters, fields=formatted_fields, or_filters=or_filters, limit_start=start, limit_page_length=page_length, order_by=order_by, ignore_permissions=ignore_permissions, reference_doctype=reference_doctype, as_list=not as_dict) if doctype in UNTRANSLATED_DOCTYPES: values = tuple([v for v in list(values) if re.search(txt+".*", (_(v.name) if as_dict else _(v[0])), re.IGNORECASE)]) # remove _relevance from results if as_dict: for r in values: r.pop("_relevance") frappe.response["values"] = values else: frappe.response["values"] = [r[:-1] for r in values]
def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_len=10, filters=None, as_dict=False): if isinstance(filters, basestring): import json filters = json.loads(filters) meta = frappe.get_meta(doctype) if not searchfield: searchfield = "name" standard_queries = frappe.get_hooks().standard_queries or {} if query and query.split()[0].lower() != "select": # by method frappe.response["values"] = frappe.call( query, doctype, txt, searchfield, start, page_len, filters, as_dict=as_dict) elif not query and doctype in standard_queries: # from standard queries search_widget(doctype, txt, standard_queries[doctype][0], searchfield, start, page_len, filters) else: if query: frappe.throw("This query style is discontinued") # custom query # frappe.response["values"] = frappe.db.sql(scrub_custom_query(query, searchfield, txt)) else: if isinstance(filters, dict): filters_items = filters.items() filters = [] for f in filters_items: if isinstance(f[1], (list, tuple)): filters.append([doctype, f[0], f[1][0], f[1][1]]) else: filters.append([doctype, f[0], "=", f[1]]) if filters is None: filters = [] or_filters = [] if meta.title_field: title_field = meta.title_field else: title_field = None print "title_field = {0}".format(title_field) # build from doctype if txt: search_fields = ["name"] if meta.search_fields: search_fields.extend(meta.get_search_fields()) if title_field and title_field not in search_fields: search_fields.append(title_field) for f in search_fields: fmeta = meta.get_field(f.strip()) if f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor"]): or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) if meta.get("fields", {"fieldname": "enabled", "fieldtype": "Check"}): filters.append([doctype, "enabled", "=", 1]) if meta.get("fields", {"fieldname": "disabled", "fieldtype": "Check"}): filters.append([doctype, "disabled", "!=", 1]) fields = get_std_fields_list(meta, searchfield or "name") if title_field: fields.insert(0, "name") fields.append("{} as `title`".format(frappe.db.escape(title_field))) else: fields.append("NULL as `title`") # find relevance as location of search term from the beginning of string # `name`. used for sorting results. fields.append("""locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""".format( _txt=frappe.db.escape((txt or "").replace("%", "")), doctype=frappe.db.escape(doctype))) # In order_by, `idx` gets second priority, because it stores link count from frappe.model.db_query import get_order_by order_by_based_on_meta = get_order_by(doctype, meta) order_by = "if(_relevance, _relevance, 99999), idx desc, {0}".format(order_by_based_on_meta) values = frappe.get_list(doctype, filters=filters, fields=fields, or_filters=or_filters, limit_start=start, limit_page_length=page_len, order_by=order_by, ignore_permissions=True if doctype == "DocType" else False, # for dynamic links as_list=not as_dict) # remove _relevance from results frappe.response["values"] = [r[:-1] for r in values]