def _search2(request, query): querystring = query.query_string query_params = QueryDict(querystring) normalized = normalize_querystring(query_params) if normalized != querystring: raise NonNormalQuerystring(normalized) querystring = normalized report = sql.get_or_create_report(query.raw_sql, query.human_query, querystring, query.report_data) if report.status is None: method = settings.AKTIVATOR_REPORT_POLLING_METHOD assert method in ("synchronous", "celery", "thread", "cron") if method == "celery": from akcrm.search.tasks import poll_report poll_report.delay(report) elif method == "thread": import threading threading.Thread(target=report.poll_results).start() elif method == "synchronous": report.poll_results() elif method == "cron": raise NotImplementedError() return report
def build_query(querystring, queryset_modifier_fn=None): query_params = QueryDict(querystring) normalized = normalize_querystring(query_params) if normalized != querystring: raise NonNormalQuerystring(normalized) querystring = normalized base_user_query = CoreUser.objects.using("ak").order_by("id") includes = [] include_pattern = re.compile("^include:\d+$") for key in query_params.keys(): if (include_pattern.match(key) and query_params[key] and (not query_params[key].endswith('_istoggle'))): includes.append((key, query_params.getlist(key))) human_query = [] all_user_queries = [] for include_group in includes: users = base_user_query _human_query = [] for item in include_group[1]: ## "distance" is handled in a group with "zipcode", so we ignore it here if item == "zipcode__distance": continue ## same for "contacted_by", in a group with "contacted_since" if item == "contacted_since__contacted_by": continue if item == "contacted_by__contacted_since": continue ## ditto if item == 'more_actions__since': continue possible_values = query_params.getlist( "%s_%s" % (include_group[0], item)) if len(possible_values) == 0: continue query_data = QUERIES[item] extra_data = {} istogglename = '%s_%s_istoggle' % (include_group[0], item) istoggle = query_params.get(istogglename, '1') try: istoggle = bool(int(istoggle)) except ValueError: istoggle = True extra_data['istoggle'] = istoggle ## XXX special cased zip code and distance # these two fields are together, if we have another case like this # we should probably formalize this if item == "zipcode": distance = query_params.get('%s_zipcode__distance' % include_group[0]) if distance: extra_data['distance'] = distance ## XXX special cased contacted_since and contacted_by # these two fields are together, if we have another case like this # we should probably formalize this if item == "contacted_since": contacted_by = query_params.get( '%s_contacted_since__contacted_by' % include_group[0]) if contacted_by: extra_data['contacted_by'] = contacted_by if item == "contacted_by": contacted_since = query_params.get( '%s_contacted_by__contacted_since' % include_group[0]) if contacted_since: extra_data['contacted_since'] = contacted_since if item == "emails_opened": since = query_params.get('%s_emails_opened__since' % include_group[0]) if since: extra_data['since'] = since if item == "more_actions": since = query_params.get('%s_more_actions__since' % include_group[0]) if since: extra_data['since'] = since if item == "donated_more": since = query_params.get('%s_donated_more__since' % include_group[0]) if since: extra_data['since'] = since if item == "donated_times": since = query_params.get('%s_donated_times__since' % include_group[0]) if since: extra_data['since'] = since make_query_fn = query_data.get('query_fn', make_default_user_query) users, __human_query = make_query_fn( users, query_data, possible_values, item, extra_data) _human_query.append(__human_query) if not _human_query or ( users.query.sql_with_params() == base_user_query.query.sql_with_params()): continue all_user_queries.append(users) human_query.append("(%s)" % " and ".join(_human_query)) human_query = "\n or ".join(human_query) users = None for i, query in enumerate(all_user_queries): if i == 0: users = query else: users = users | query if users is None: users = base_user_query ### If both of user_name and user_email are filled out, ### search for anyone who matches EITHER condition, rather than both. extra_where = [] extra_params = [] if query_params.get("user_name"): extra_where.append( "CONCAT(`core_user`.`first_name`, ' ', `core_user`.`last_name`) LIKE %s") extra_params.append("%" + "%".join(query_params['user_name'].split()) + "%") human_query += "\n and name is like \"%s\"" % query_params['user_name'] if query_params.get("user_email"): extra_where.append("`core_user`.`email` LIKE %s") extra_params.append("%" + query_params.get("user_email") + "%") human_query += "\n and email is like \"%s\"" % query_params['user_email'] if len(extra_where): if len(extra_where) == 2: extra_where = ["(%s OR %s)" % tuple(extra_where)] users = users.extra( where=extra_where, params=extra_params) users = users.extra(select={'phone': ( "SELECT `normalized_phone` FROM `core_phone` " "WHERE `core_phone`.`user_id`=`core_user`.`id` " "LIMIT 1"), 'campus': ( "SELECT `value` from `core_userfield` " "WHERE`core_userfield`.`parent_id`=`core_user`.`id` " 'AND `core_userfield`.`name`="campus" LIMIT 1'), 'name': ( "CONCAT(CONCAT(first_name, \" \"), last_name)"), 'skills': ( "SELECT `value` from `core_userfield` " "WHERE`core_userfield`.`parent_id`=`core_user`.`id` " 'AND `core_userfield`.`name`="skills" LIMIT 1'), 'engagement_level': ( "SELECT `value` from `core_userfield` " "WHERE`core_userfield`.`parent_id`=`core_user`.`id` " 'AND `core_userfield`.`name`="engagement_level" LIMIT 1'), 'affiliation': ( "SELECT `value` from `core_userfield` " "WHERE`core_userfield`.`parent_id`=`core_user`.`id` " 'AND `core_userfield`.`name`="affiliation" LIMIT 1'), }) if users.query.sql_with_params() == base_user_query.query.sql_with_params(): users = base_user_query.none() if queryset_modifier_fn is not None: users = queryset_modifier_fn(users) if not query_params.get('subscription_all_users', False): users = users.filter(subscription_status='subscribed') human_query += "\n and subscription_status is 'subscribed'" users = users.distinct() raw_sql = sql.raw_sql_from_queryset(users) del users return Query(human_query, querystring, raw_sql, None)