Django search form help want to be able to do partial search as well
I have a search for that looks for an alternate_id for a particular item. This search for can allow alternative if to do multiple searches if there is a comma without spaces. But I want my search form to be able to do a "partial search" as well. So searching for a*,2ndid will give all results a......,2ndid开发者_C百科
Alternate id is a string. Not an integer. The only reason why I have as __in
was because I could perform multiple searches.
def search_item(request, client_id = 0):
client = None
if client_id != 0:
try:
client = models.Client.objects.get(pk = client_id)
except:
pass
items = None
Q_alt_ids = Q()
if request.method == 'POST':
form = forms.SearchItemForm(request.POST)
if form.is_valid():
alternate_id = form.cleaned_data['alternate_id']
items = client.storageitem_set.all()
if alternate_id:
alternate_ids= alternate_id.lower().split(",")
Q_alt_ids = Q(alternative_id__in = alternate_ids)
return render_to_response('items.html', {'items':items, 'client':client}, context_instance = RequestContext(request))
else:
HttpResponse(client)
if client is not None:
form = forms.SearchItemForm(initial = {'client':client.pk})
else:
form = forms.SearchItemForm()
return render_to_response('search_items.html', {'form':form}, context_instance = RequestContext(request))
Aside from writing your own SQL, I think the only out of the box solution that can handle a robust query like a wildcard is a regular expression. If the wildcard is always in the same place, such as followed by a partial string, you could use the field__startswith=partial
lookup type.
But in general, wildcards = regex
http://docs.djangoproject.com/en/dev/ref/models/querysets/#iregex
BUT,
I have a sneaking suspicion you might be looking for the contains
or icontains
filter lookup type.
If you want to match 'hello', 'ello', 'world' in 'hello world':
# first split the string by comma
queries = form.cleaned_data.get('query', '').split(',')
# populate queries list
query_list = [Q(**{'alternative_id__icontains' : query }) for query in queries]
# join queries list with the OR operator
results = MyModel.objects.filter( reduce(operator.or_, query_list) )
thanks yuji for the answer. These change are needed to make it work.
return_all = False
filters = []
if alternate_id:
alternate_ids = alternate_id.lower().split(",")
for item in alternate_ids:
if '*' not in item:
filters.append( Q(alternative_id=item) )
elif item == '*':
return_all = True
elif item.startswith('*') and item.endswith('*'):
filters.append( Q(alternative_id__icontains=item.strip('*')) )
elif item.startswith('*'):
filters.append( Q(alternative_id__endswith=item.strip('*')) )
elif item.endswith('*'):
filters.append( Q(alternative_id__startswith=item.strip('*')) )
else:
assert False, "Wildcard in invalid position (valid is.. *XX, *XX*, XX*)"
if not filters or return_all:
items = items.all()
else:
items = items.filter(reduce(operator.or_, filters))
精彩评论