tags:

views:

152

answers:

3

I've got a really simple blog application and I want to add a really simple search feature to it.

There are 3 key fields to my model.

class BlogPost(models.Model):
    title = models.CharField(max_length=100) # the title
    intro = models.TextField(blank=True, null=True) # an extract
    content = models.TextField(blank=True, null=True) # full post

I don't need a Google. I don't want to search comments (which are held on Disqus anyway). I just want a date-ranked, keyword filtered set of posts.

Everything I find on Google for some form of "django" and "search" comes back with hideously complicated Haystack+backend solutions. I don't need all that. I don't want to eat up more resources on a low-usage feature (I used to have a search box before I ported to Django and it had perhaps 4 searches a month).

The reason I'm taking time to ask on here (rather than just writing a messy little script) is this already exists in the admin. You can set the columns to search on and then just search and it "just works".

Is there some way of getting a handle on the admin-provided search and pulling it into my user-facing app?

+2  A: 

You would use the __search operator. It's documented in the Django QuerySet API Reference. There's also istartswith, which does a case-insensitive starts-with search.

Here's a working example (adapted from my own Django site):

def search(request):
    try:
        q = request.GET['q']
        posts = BlogPost.objects.filter(title__search=q) | \
                BlogPost.objects.filter(intro__search=q) | \
                BlogPost.objects.filter(content__search=q)
        return render_to_response('search/results.html', {'posts':posts, 'q':q})
    except KeyError:
        return render_to_response('search/results.html')
Frederik
+5  A: 

If you want a really simple search you can use icontains lookup and Q object:

from django.db.models import Q
results = BlogPost.objects.filter(Q(title__icontains=your_search_query) | Q(intro__icontains=your_search_query) | Q(content__icontains=your_search_query)).order_by('pub_date')

You should also note that Haystack doesn't have to be "hideously complicated". You can set up haystack with Whoosh backend in less then 15 minutes.

Ludwik Trammer
I concur, Haystack+Whoosh is pretty easy to get going. Might as well go with google site search if even that's too much effort.
Stijn Debrouwere
By complicated I didn't just mean the setup. It's miles more code than this one-liner. I know it *does* a lot more with a lot better performance but quick, dirty search is all I'm after at the moment. Thanks! @Stijn pulling in another search engine (I'd go with Bing because they have a proper server-side API still) will be my next port of call if dirty searching doesn't work out.
Oli
+2  A: 

From the django source: http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/views/main.py

# Apply keyword searches.
def construct_search(field_name):
    if field_name.startswith('^'):
        return "%s__istartswith" % field_name[1:]
    elif field_name.startswith('='):
        return "%s__iexact" % field_name[1:]
    elif field_name.startswith('@'):
        return "%s__search" % field_name[1:]
    else:
        return "%s__icontains" % field_name

if self.search_fields and self.query:
    for bit in self.query.split():
        or_queries = [models.Q(**{construct_search(str(field_name)): bit}) for field_name in self.search_fields]
        qs = qs.filter(reduce(operator.or_, or_queries))
    for field_name in self.search_fields:
        if '__' in field_name:
            qs = qs.distinct()
            break

clearly, it uses the database options to perform search. If nothing else, you should be able to reuse some of the code from it.

So says the documentation too: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields

The full text search, however, uses the mysql index (only if you are using mysql).

Lakshman Prasad