我想在搜索查询中添加功能以按任何列字段进行搜索。目前,搜索是按名称进行的。
我该怎么做?
class ApplicationList(APIView):
permission_classes = (IsAuthenticated,)
# parser_classes = (JSONParser,)
def post(self, request, format=None):
# Get a list of fields dynamically
fields = list()
for f in Application._meta.fields:
if f.is_relation:
continue
fields.append(f.name)
queryset = Application.objects_with_sprint_name.all()
# Looking for a specific bubble?
if 'bubble' in request.data:
if request.data['bubble'] == '4-1':
queryset = queryset.filter(assessment_phase__id=request.data['bubble']).exclude(attributes__contains={'application_disposition':'Removed'})
else:
queryset = queryset.filter(assessment_phase__id=request.data['bubble'])
# Providing a search query?
if 'search' in request.data:
q_search = request.data['search']
# Build the query
q = get_query(q_search, fields)
queryset = queryset.filter(q)
if 'filter' in request.data:
q = get_filter(request.data['filter'])
if q:
queryset = queryset.filter(q)
page = int(request.data.get('page', 1))
per_page = int(request.data.get('per_page', 25))
# Sorting
sort_by = request.data.get('sort_by', 'name') or 'name'
sort_dir = request.data.get('sort_dir', 'asc') or 'asc'
if sort_dir == 'desc':
sort_dir = '-'
else:
sort_dir = ''
# Is this an actual field or do we need to sort by the attributes__*?
if sort_by not in fields:
sort_by = 'attributes__' + sort_by
queryset = queryset.order_by('{0}{1}'.format(sort_dir, sort_by))
# Do a little data massaging
untreated_data = queryset.values()
data = list()
for app in untreated_data:
this_app = {}
for k, v in app.items():
if k == 'attributes':
continue
if k == 'sprint_name':
this_app[k] = v
this_app['sprint'] = v
continue
this_app[k] = v
this_app.update(app['attributes'])
data.append(this_app)
start = (page-1) * per_page
end = (page) * per_page
response = {
'total_rows': len(data),
'data': data[start:end],
}
return Response(response)
#Util.py
def normalize_query(query_string,
findterms=re.compile(r'r'""([^"]+)"|(\S+)').findall,
normspace=re.compile(r'\s{2,}').sub):
''' Splits the query string in invidual keywords, getting rid of unnecessary spaces
and grouping quoted words together.
Example:
>>> normalize_query(' some random words "with quotes " and spaces')
['some', 'random', 'words', 'with quotes', 'and', 'spaces']
'''
return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)]
def get_query(query_string, search_fields):
''' Returns a query, that is a combination of Q objects. That combination
aims to search keywords within a model by testing the given search fields.
'''
query = None # Query to search for every search term
terms = normalize_query(query_string)
for term in terms:
or_query = None # Query to search for a given term in each field
for field_name in search_fields:
q = Q(**{"%s__icontains" % field_name: term})
if or_query is None:
or_query = q
else:
or_query = or_query | q
if query is None:
query = or_query
else:
query = query & or_query
return query
def get_filter(filter_dict):
available_fields = [ field.name for field in Application._meta.fields ] \
+ ApplicationManager.annotated_fields
query = None
if filter_dict is None:
return query
for field_name, val in filter_dict.items():
query_field = field_name
# Quicksearch box
if field_name == '_quicksearch_':
q = Q(name__icontains=val)
if query is None:
query = q
else:
query = query & q
continue
# Figure out if this field is part of the model
# or in the attributes json field
if query_field not in available_fields:
query_field = 'attributes__{0}'.format(query_field)
if isinstance(val, list):
q = None
# Are we looking for null or blank?
if '#is_null_or_blank#' in val:
val.remove('#is_null_or_blank#')
q = Q(**{"%s__isnull" % query_field: True}) | \
Q(**{query_field: ''}) | \
Q(**{query_field: []})
# Loop through the list and create some "OR" expressions
for v in val:
tmp = Q(**{"%s__contains" % query_field: v})
if q is None:
q = tmp
q = q | tmp
elif val.startswith('#bool#'):
bval = val[6:].lower() == 'true'
q = Q(**{"%s" % query_field: bval})
else:
q = Q(**{"%s__icontains" % query_field: val})
# Add to our master query of all fields
if query is None:
query = q
else:
query = query & q
return query