File: generics.py

package info (click to toggle)
drf-haystack 1.9.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 564 kB
  • sloc: python: 2,608; makefile: 147
file content (104 lines) | stat: -rw-r--r-- 4,079 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals

import six

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

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

from drf_haystack.filters import HaystackFilter


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]

    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

    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.")

    def filter_queryset(self, queryset):
        queryset = super(HaystackGenericAPIView, self).filter_queryset(queryset)
        
        if self.load_all:
            queryset = queryset.load_all()

        return queryset