简体   繁体   中英

Search through multiple fields in Django

I'm trying to build a search system, and I want to search by multiple fields name, 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.

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

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>]

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)

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 ,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM