Source code for drf_haystack.mixins

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

from __future__ import absolute_import, unicode_literals

from rest_framework.decorators import action
from rest_framework.response import Response

from drf_haystack.filters import HaystackFacetFilter


[docs]class MoreLikeThisMixin(object): """ Mixin class for supporting "more like this" on an API View. """
[docs] @action(detail=True, methods=["get"], url_path="more-like-this") def more_like_this(self, request, pk=None): """ Sets up a detail route for ``more-like-this`` results. Note that you'll need backend support in order to take advantage of this. This will add ie. ^search/{pk}/more-like-this/$ to your existing ^search pattern. """ obj = self.get_object().object queryset = self.filter_queryset(self.get_queryset()).more_like_this(obj) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
[docs]class FacetMixin(object): """ Mixin class for supporting faceting on an API View. """ facet_filter_backends = [HaystackFacetFilter] facet_serializer_class = None facet_objects_serializer_class = None facet_query_params_text = 'selected_facets'
[docs] @action(detail=False, methods=["get"], url_path="facets") def facets(self, request): """ Sets up a list route for ``faceted`` results. This will add ie ^search/facets/$ to your existing ^search pattern. """ queryset = self.filter_facet_queryset(self.get_queryset()) for facet in request.query_params.getlist(self.facet_query_params_text): if ":" not in facet: continue field, value = facet.split(":", 1) if value: queryset = queryset.narrow('%s:"%s"' % (field, queryset.query.clean(value))) serializer = self.get_facet_serializer(queryset.facet_counts(), objects=queryset, many=False) return Response(serializer.data)
[docs] def filter_facet_queryset(self, queryset): """ Given a search queryset, filter it with whichever facet filter backends in use. """ for backend in list(self.facet_filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) if self.load_all: queryset = queryset.load_all() return queryset
[docs] def get_facet_serializer(self, *args, **kwargs): """ Return the facet serializer instance that should be used for serializing faceted output. """ assert "objects" in kwargs, "`objects` is a required argument to `get_facet_serializer()`" facet_serializer_class = self.get_facet_serializer_class() kwargs["context"] = self.get_serializer_context() kwargs["context"].update({ "objects": kwargs.pop("objects"), "facet_query_params_text": self.facet_query_params_text, }) return facet_serializer_class(*args, **kwargs)
[docs] def get_facet_serializer_class(self): """ Return the class to use for serializing facets. Defaults to using ``self.facet_serializer_class``. """ if self.facet_serializer_class is None: raise AttributeError( "%(cls)s should either include a `facet_serializer_class` attribute, " "or override %(cls)s.get_facet_serializer_class() method." % {"cls": self.__class__.__name__} ) return self.facet_serializer_class
[docs] def get_facet_objects_serializer(self, *args, **kwargs): """ Return the serializer instance which should be used for serializing faceted objects. """ facet_objects_serializer_class = self.get_facet_objects_serializer_class() kwargs["context"] = self.get_serializer_context() return facet_objects_serializer_class(*args, **kwargs)
[docs] def get_facet_objects_serializer_class(self): """ Return the class to use for serializing faceted objects. Defaults to using the views ``self.serializer_class`` if not ``self.facet_objects_serializer_class`` is set. """ return self.facet_objects_serializer_class or super(FacetMixin, self).get_serializer_class()