Reputation: 1519
I'm trying to build a search system, and I want to search by multiple fieldsname, state, city,
in my django models. I wrote the below code, yet I've been unable to figure out how to go about it.
Models:
class Finhall(models.Model):
user=models.ForeignKey(User)
name=models.CharField(max_length=250, unique=True)
address=models.CharField(max_length=200)
city=models.CharField(max_length=200)
state=models.CharField(max_length=200)
def __unicode__(self):
return u'%s' % (self.name)
Views.py
def hup_find(request):
if ('q' in request.GET) and request.GET['q'].strip():
query_string=request.GET.get('q')
seens=Finhall.objects.filter(name__icontains=query_string)
else:
seens=None
return render_to_response('find.html',{'seens':seens},context_instance=RequestContext(request))
Template:
{% block content %}
<body>
<form action="" method="GET">
<input type="text" name="q" />
<button type="submit">search</button>
</form>
{% for seen in seens %}
<p> {{seen.name}}</p>
{% empty %}
<p> no search </p>
{% endfor %}
</body>
{% endblock %}
How can I go about this? I don't want to use haysatck due to some personal reasons.
Upvotes: 10
Views: 32900
Reputation: 1383
As Robin Nemeth suggested, if you are using postgres db, can use the SearchVector, (I'm just making it straight to the question, get full details in django documentation.)
First add django.contrib.postgres
to the INSTALLED_APPS
, helps leveraging PostgreSQL’s full text search engine.
in the views.py of the search,
from django.contrib.postgres.search import SearchVector
# view function
def hup_find(request):
search_vector = SearchVector('name', 'state', 'city')
if ('q' in request.GET) and request.GET['q'].strip():
query_string=request.GET['q']
seens = Findhall.objects.annotate(
search=search_vector).filter(search=query_string)
return render(request, 'find.html', {'seens':seens})
For large databases the search process takes some time, you can improve the performance using use GIN-(Generalized Inverted Index) feature of postgresql, These are some helpful links other than the official documentation,
There is different approach found, I think employing search in a more pythonish way by Julien Phalip,
Upvotes: 5
Reputation: 55972
you can use django Q
objects to do OR
query,
or if you want to AND
your queries together just use the current lookups as kwargs
seens = Finhall.objects.filter(
name__icontains=query_string,
address__icontains=query_string
)
You should really consider full text search or haystack
(which makes search easy) because icontains
issues a %LIKE%
which is not remotely scalable
Upvotes: 19
Reputation: 7162
To search same text in multiple fields you can use this :
from django.db.models import Q
class SearchAPI(APIView):
def get(self, request, search_text, format=None, **kwargs):
Model.objects.filter(Q(search_tags__contains=search_text) | Q(auto_tags__contains=search_text)
Upvotes: 9
Reputation: 3969
EDIT: Just noticed it is Postgres only
Apparently in django 1.10 SearchVector class was added.
Usage from the docs:
Searching against a single field is great but rather limiting. The Entry instances we’re searching belong to a Blog, which has a tagline field. To query against both fields, use a SearchVector:
>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
... search=SearchVector('body_text', 'blog__tagline'),
... ).filter(search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
Upvotes: 13