Source code for drf_haystack.generics

# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals

from django.contrib.contenttypes.models import ContentType
from django.http import Http404
from django.utils import six

from haystack.backends import SQ
from haystack.query import SearchQuerySet
from rest_framework.generics import GenericAPIView

from drf_haystack.filters import HaystackFilter


[docs]class HaystackGenericAPIView(GenericAPIView): """ Base class for all haystack generic views. """ # Use `index_models` to filter on which search index models we # should include in the search result. index_models = [] object_class = SearchQuerySet query_object = SQ # Override document_uid_field with whatever field in your index # you use to uniquely identify a single document. This value will be # used wherever the view references the `lookup_field` kwarg. document_uid_field = "id" lookup_sep = "," # If set to False, DB lookups are done on a per-object basis, # resulting in in many individual trips to the database. If True, # the SearchQuerySet will group similar objects into a single query. load_all = False filter_backends = [HaystackFilter]
[docs] def get_queryset(self, index_models=[]): """ Get the list of items for this view. Returns ``self.queryset`` if defined and is a ``self.object_class`` instance. @:param index_models: override `self.index_models` """ if self.queryset is not None and isinstance(self.queryset, self.object_class): queryset = self.queryset.all() else: queryset = self.object_class()._clone() if len(index_models): queryset = queryset.models(*index_models) elif len(self.index_models): queryset = queryset.models(*self.index_models) return queryset
[docs] def get_object(self): """ Fetch a single document from the data store according to whatever unique identifier is available for that document in the SearchIndex. In cases where the view has multiple ``index_models``, add a ``model`` query parameter containing a single `app_label.model` name to the request in order to override which model to include in the SearchQuerySet. Example: /api/v1/search/42/?model=myapp.person """ queryset = self.get_queryset() if "model" in self.request.query_params: try: app_label, model = map(six.text_type.lower, self.request.query_params["model"].split(".", 1)) ctype = ContentType.objects.get(app_label=app_label, model=model) queryset = self.get_queryset(index_models=[ctype.model_class()]) except (ValueError, ContentType.DoesNotExist): raise Http404("Could not find any models matching '%s'. Make sure to use a valid " "'app_label.model' name for the 'model' query parameter." % self.request.query_params["model"]) lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field if lookup_url_kwarg not in self.kwargs: raise AttributeError( "Expected view %s to be called with a URL keyword argument " "named '%s'. Fix your URL conf, or set the `.lookup_field` " "attribute on the view correctly." % (self.__class__.__name__, lookup_url_kwarg) ) queryset = queryset.filter(self.query_object((self.document_uid_field, self.kwargs[lookup_url_kwarg]))) count = queryset.count() if count == 1: return queryset[0] elif count > 1: raise Http404("Multiple results matches the given query. Expected a single result.") raise Http404("No result matches the given query.")
[docs] def filter_queryset(self, queryset): queryset = super(HaystackGenericAPIView, self).filter_queryset(queryset) if self.load_all: queryset = queryset.load_all() return queryset