File: 01_intro.rst

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 (212 lines) | stat: -rw-r--r-- 5,884 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
.. _basic-usage-label:

===========
Basic Usage
===========

Usage is best demonstrated with some simple examples.

.. warning::

    The code here is for demonstration purposes only! It might work (or not, I haven't
    tested), but as always, don't blindly copy code from the internet.

Examples
========

models.py
---------

Let's say we have an app which contains a model `Location`. It could look something like this.

.. code-block:: python

    #
    # models.py
    #

    from django.db import models
    from haystack.utils.geo import Point


    class Location(models.Model):

        latitude = models.FloatField()
        longitude = models.FloatField()
        address = models.CharField(max_length=100)
        city = models.CharField(max_length=30)
        zip_code = models.CharField(max_length=10)

        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)

        def __str__(self):
            return self.address

        @property
        def coordinates(self):
            return Point(self.longitude, self.latitude)


.. _search-index-example-label:

search_indexes.py
-----------------

We would have to make a ``search_indexes.py`` file for haystack to pick it up.

.. code-block:: python

    #
    # search_indexes.py
    #

    from django.utils import timezone
    from haystack import indexes
    from .models import Location


    class LocationIndex(indexes.SearchIndex, indexes.Indexable):

        text = indexes.CharField(document=True, use_template=True)
        address = indexes.CharField(model_attr="address")
        city = indexes.CharField(model_attr="city")
        zip_code = indexes.CharField(model_attr="zip_code")

        autocomplete = indexes.EdgeNgramField()
        coordinates = indexes.LocationField(model_attr="coordinates")

        @staticmethod
        def prepare_autocomplete(obj):
            return " ".join((
                obj.address, obj.city, obj.zip_code
            ))

        def get_model(self):
            return Location

        def index_queryset(self, using=None):
            return self.get_model().objects.filter(
                created__lte=timezone.now()
            )


views.py
--------

For a generic Django REST Framework view, you could do something like this.

.. code-block:: python

    #
    # views.py
    #

    from drf_haystack.serializers import HaystackSerializer
    from drf_haystack.viewsets import HaystackViewSet

    from .models import Location
    from .search_indexes import LocationIndex


    class LocationSerializer(HaystackSerializer):

        class Meta:
            # The `index_classes` attribute is a list of which search indexes
            # we want to include in the search.
            index_classes = [LocationIndex]

            # The `fields` contains all the fields we want to include.
            # NOTE: Make sure you don't confuse these with model attributes. These
            # fields belong to the search index!
            fields = [
                "text", "address", "city", "zip_code", "autocomplete"
            ]


    class LocationSearchView(HaystackViewSet):

        # `index_models` is an optional list of which models you would like to include
        # in the search result. You might have several models indexed, and this provides
        # a way to filter out those of no interest for this particular view.
        # (Translates to `SearchQuerySet().models(*index_models)` behind the scenes.
        index_models = [Location]

        serializer_class = LocationSerializer


urls.py
-------

Finally, hook up the views in your `urls.py` file.

.. note::

    Make sure you specify the `basename` attribute when wiring up the view in the router.
    Since we don't have any single `model` for the view, it is impossible for the router to
    automatically figure out the base name for the view.

.. code-block:: python

    #
    # urls.py
    #

    from django.conf.urls import patterns, url, include
    from rest_framework import routers

    from .views import LocationSearchView

    router = routers.DefaultRouter()
    router.register("location/search", LocationSearchView, basename="location-search")


    urlpatterns = patterns(
        "",
        url(r"/api/v1/", include(router.urls)),
    )


Query time!
-----------

Now that we have a view wired up, we can start using it.
By default, the `HaystackViewSet` (which, more importantly inherits the `HaystackGenericAPIView`
class) is set up to use the `HaystackFilter`. This is the most basic filter included and can do
basic search by querying any of the field included in the `fields` attribute on the
`Serializer`.

.. code-block:: none

    http://example.com/api/v1/location/search/?city=Oslo

Would perform a query looking up all documents where the `city field` equals "Oslo".


Field Lookups
.............

You can also use field lookups in your field queries. See the
Haystack `field lookups <https://django-haystack.readthedocs.io/en/latest/searchqueryset_api.html?highlight=lookups#id1>`_
documentation for info on what lookups are available.  A query using a lookup might look like the
following:

.. code-block:: none

    http://example.com/api/v1/location/search/?city__startswith=Os

This would perform a query looking up all documents where the `city field` started with "Os".
You might get "Oslo", "Osaka", and "Ostrava".

Term Negation
.............

You can also specify terms to exclude from the search results using the negation keyword.
The default keyword is ``not``, but is configurable via settings using ``DRF_HAYSTACK_NEGATION_KEYWORD``.

.. code-block:: none

    http://example.com/api/v1/location/search/?city__not=Oslo
    http://example.com/api/v1/location/search/?city__not__contains=Los
    http://example.com/api/v1/location/search/?city__contains=Los&city__not__contains=Angeles