debian-django-watson/watson/views.py

125 lines
3.6 KiB
Python

"""Views used by the built-in site search functionality."""
from __future__ import unicode_literals
import json
from django.shortcuts import redirect
from django.http import HttpResponse
from django.utils import six
from django.views import generic
from django.views.generic.list import BaseListView
from watson import search as watson
class SearchMixin(object):
"""Base mixin for search views."""
context_object_name = "search_results"
query_param = "q"
def get_query_param(self):
"""Returns the query parameter to use in the request GET dictionary."""
return self.query_param
models = ()
def get_models(self):
"""Returns the models to use in the query."""
return self.models
exclude = ()
def get_exclude(self):
"""Returns the models to exclude from the query."""
return self.exclude
def get_queryset(self):
"""Returns the initial queryset."""
return watson.search(self.query, models=self.get_models(), exclude=self.get_exclude())
def get_query(self, request):
"""Parses the query from the request."""
return request.GET.get(self.get_query_param(), "").strip()
empty_query_redirect = None
def get_empty_query_redirect(self):
"""Returns the URL to redirect an empty query to, or None."""
return self.empty_query_redirect
extra_context = {}
def get_extra_context(self):
"""
Returns any extra context variables.
Required for backwards compatibility with old function-based views.
"""
return self.extra_context
def get_context_data(self, **kwargs):
"""Generates context variables."""
context = super(SearchMixin, self).get_context_data(**kwargs)
context["query"] = self.query
# Process extra context.
for key, value in six.iteritems(self.get_extra_context()):
if callable(value):
value = value()
context[key] = value
return context
def get(self, request, *args, **kwargs):
"""Performs a GET request."""
self.query = self.get_query(request)
if not self.query:
empty_query_redirect = self.get_empty_query_redirect()
if empty_query_redirect:
return redirect(empty_query_redirect)
return super(SearchMixin, self).get(request, *args, **kwargs)
class SearchView(SearchMixin, generic.ListView):
"""View that performs a search and returns the search results."""
template_name = "watson/search_results.html"
class SearchApiView(SearchMixin, BaseListView):
"""A JSON-based search API."""
def render_to_response(self, context, **response_kwargs):
"""Renders the search results to the response."""
content = json.dumps({
"results": [
{
"title": result.title,
"description": result.description,
"url": result.url,
"meta": result.meta,
} for result in context[self.get_context_object_name(self.get_queryset())]
]
}).encode("utf-8")
# Generate the response.
response = HttpResponse(content, **response_kwargs)
response["Content-Type"] = "application/json; charset=utf-8"
response["Content-Length"] = len(content)
return response
# Older function-based views.
def search(request, **kwargs):
"""Renders a page of search results."""
return SearchView.as_view(**kwargs)(request)
def search_json(request, **kwargs):
"""Renders a JSON representation of matching search entries."""
return SearchApiView.as_view(**kwargs)(request)