Last active
November 8, 2017 08:26
-
-
Save galileoguzman/559a5af3869c33f3a85a52d77533906f to your computer and use it in GitHub Desktop.
Make view for search inside Django web app with a query string and return template with pagination options.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import unicode_literals | |
from django.db import models | |
from autoslug import AutoSlugField | |
from ckeditor.fields import RichTextField | |
from django.template.defaultfilters import slugify | |
class Post(models.Model): | |
title = models.CharField(max_length=75) | |
body = RichTextField('body') | |
post_status = models.CharField(max_length=11) | |
created_at = models.DateTimeField(auto_now_add=True) | |
updated_at = models.DateTimeField(auto_now=True) | |
slug = AutoSlugField(populate_from='title', unique_with='created_at', max_length=100, always_update=True, unique=True) | |
@models.permalink | |
def get_absolute_url(self): | |
return 'article:post', (self.slug,) | |
def __str__(self): | |
return self.title |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
from django.db.models import Q | |
def normalize_query(query_string, findterms=re.compile(r'"([^"]+)"|(\S+)').findall, normspace=re.compile(r'\s{2,}').sub): | |
''' | |
Splits the query string in invidual keywords, getting rid of unecessary spaces | |
and grouping quoted words together. | |
Example: | |
>>> normalize_query(' some random words "with quotes " and spaces') | |
['some', 'random', 'words', 'with quotes', 'and', 'spaces'] | |
''' | |
return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)] | |
def get_query(query_string, search_fields): | |
''' | |
Returns a query, that is a combination of Q objects. That combination aims to search keywords within a model by testing the given search fields. | |
''' | |
query = None # Query to search for every search term | |
terms = normalize_query(query_string) | |
for term in terms: | |
or_query = None # Query to search for a given term in each field | |
for field_name in search_fields: | |
q = Q(**{"%s__icontains" % field_name: term}) | |
if or_query is None: | |
or_query = q | |
else: | |
or_query = or_query | q | |
if query is None: | |
query = or_query | |
else: | |
query = query & or_query | |
return query |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# urls.py | |
from django.conf.urls import include, url | |
from posts import views as posts_views | |
urlpatterns = [ | |
url(r'^search/(?P<phrase>.*)$', posts_views.search, name="search"), | |
url(r"^article/(?P<slug>.*)$", posts_views.article, name="article"), | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.shortcuts import render, get_object_or_404 | |
from django.db.models import Q | |
from posts.models import Post | |
# paginator django | |
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger | |
# Use of lib | |
from helpers.search_engine import get_query | |
def search(request, phrase): | |
query_string = '' | |
found_posts = None | |
posts = None | |
if ('q' in request.GET) and request.GET['q'].strip(): | |
query_string = request.GET['q'] | |
entry_query = get_query(query_string, ['title', 'body',]) | |
found_posts = Post.objects.filter(entry_query,post_status=2).order_by('-created_at')[:50] | |
paginator = Paginator(found_posts, 8) | |
page = request.GET.get('page') | |
try: | |
posts = paginator.page(page) | |
except PageNotAnInteger: | |
# If page is not an integer, deliver first page. | |
posts = paginator.page(1) | |
except EmptyPage: | |
# If page is out of range (e.g. 9999), deliver last page of results. | |
posts = paginator.page(paginator.num_pages) | |
return render(request, 'app/results.html',{ | |
'query': query_string, | |
'posts': posts, | |
'query_string': query_string, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment