Django Simple Search
This django form class creates a search form for a model and generates a query from the submitted data.
To use, extend the BaseSearchForm class, defining a Meta class with the following values:
base_qs
The queryset to search, ie. MyModel.objects
search_fields
The fields to search, using the same syntax as the django admin directive of the same name, ie.
'fieldname'- field must contain the search string'^fieldname'- field must start with the search string'=fieldname'- field must exactly equal the search string'@fieldname'- performs a fulltext search (mysql/postgres only) on field
Related model fields can also be searched, ie 'mycategory__name' will search
the name field on the mycategory model.
fulltext_indexes
Defines the mysql fulltext indexes to search against. If this is set,
and the database engine is mysql, this setting will override search_fields. See
"Fulltext searches" below for more info.
Additional search fields
Custom fields can be added to filter the results - by default, these perform
an exact-match search on the model field of the same name. A prepare_FIELDNAME
method can be defined for each custom field for advanced queries - this method
should return a Q instance for addition to the overall query. See below for an example.
Fulltext searches
If the database engine in use is mysql, and fulltext_indexes is set, the form will perform
a fulltext search instead of constructing a query from search_fields. The format of
fulltext_indexes should be a list of tuples of the format (fields, weighting), where fields is a
comma-separated list of field names corresponding to the index, and weighting is an integer.
In the example below, matches on 'name' are weighted double what those on the rest of the
index are, meaning they should come up first in the results.
Note that only one fulltext index is required, because the 'name' match can be made against the second index.
Example form class (myapp/forms.py)
from django.db.models import Q
from simple_search import BaseSearchForm
from myapp.models import MyModel, MyCategory
class MyModelSearchForm(BaseSearchForm):
class Meta:
base_qs = MyModel.objects
search_fields = ('^name', 'description', 'specifications', '=id')
# assumes a fulltext index has been defined on the fields
# 'name,description,specifications,id'
fulltext_indexes = (
('name', 2), # name matches are weighted higher
('name,description,specifications,id', 1),
)
"""
A custom addition - the absence of a prepare_category method means
the query will search for an exact match on this field.
"""
category = forms.ModelChoiceField(
queryset = MyCategory.objects.all(),
required = False
)
"""
This field creates a custom query addition via the prepare_start_date
method.
"""
start_date = forms.DateField(
required = False,
input_formats = ('%Y-%m-%d',),
)
def prepare_start_date(self):
if self.cleaned_data['start_date']:
return Q(creation_date__gte=self.cleaned_data['start_date'])
else:
return ""
Example use in a view (myapp/views.py)
from django.shortcuts import render_to_response
from django.template import RequestContext
from myapp.forms import MyModelSearchForm
def search(request):
if request.GET:
form = MyModelSearchForm(request.GET)
if form.is_valid():
results = form.get_result_queryset()
else:
results = []
else:
form = MyModelSearchForm()
results = []
return render_to_response(
'search.html',
RequestContext(request, {
'form': form,
'results': results,
})
)
Demo
You can try it out on this site, either from the search box in the footer or here.