File: 09_multiple_indexes.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 (168 lines) | stat: -rw-r--r-- 5,487 bytes parent folder | download | duplicates (2)
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
.. _multiple-indexes-label:

Multiple search indexes
=======================

So far, we have only used one class in the ``index_classes`` attribute of our serializers.  However, you are able to specify
a list of them.  This can be useful when your search engine has indexed multiple models and you want to provide aggregate
results across two or more of them.  To use the default multiple index support, simply add multiple indexes the ``index_classes``
list

.. code-block:: python

    class PersonIndex(indexes.SearchIndex, indexes.Indexable):
        text = indexes.CharField(document=True, use_template=True)
        firstname = indexes.CharField(model_attr="first_name")
        lastname = indexes.CharField(model_attr="last_name")

        def get_model(self):
            return Person

    class PlaceIndex(indexes.SearchIndex, indexes.Indexable):
        text = indexes.CharField(document=True, use_template=True)
        address = indexes.CharField(model_attr="address")

        def get_model(self):
            return Place

    class ThingIndex(indexes.SearchIndex, indexes.Indexable):
        text = indexes.CharField(document=True, use_template=True)
        name = indexes.CharField(model_attr="name")

        def get_model(self):
            return Thing

    class AggregateSerializer(HaystackSerializer):

        class Meta:
            index_classes = [PersonIndex, PlaceIndex, ThingIndex]
            fields = ["firstname", "lastname", "address", "name"]


    class AggregateSearchViewSet(HaystackViewSet):

        serializer_class = AggregateSerializer

.. note::

    The ``AggregateSearchViewSet`` class above omits the optional ``index_models`` attribute.  This way results from all the
    models are returned.

The result from searches using multiple indexes is a list of objects, each of which contains only the fields appropriate to
the model from which the result came.  For instance if a search returned a list containing one each of the above models, it
might look like the following:

.. code-block:: javascript

    [
        {
            "text": "John Doe",
            "firstname": "John",
            "lastname": "Doe"
        },
        {
            "text": "123 Doe Street",
            "address": "123 Doe Street"
        },
        {
            "text": "Doe",
            "name": "Doe"
        }
    ]

Declared fields
---------------

You can include field declarations in the serializer class like normal.  Depending on how they are named, they will be
treated as common fields and added to every result or as specific to results from a particular index.

Common fields are declared as you would any serializer field.  Index-specific fields must be prefixed with "_<index class name>__".
The following example illustrates this usage:

.. code-block:: python

    class AggregateSerializer(HaystackSerializer):
        extra = serializers.SerializerMethodField()
        _ThingIndex__number = serializers.SerializerMethodField()

        class Meta:
            index_classes = [PersonIndex, PlaceIndex, ThingIndex]
            fields = ["firstname", "lastname", "address", "name"]

        def get_extra(self,instance):
            return "whatever"

        def get__ThingIndex__number(self,instance):
            return 42

The results of a search might then look like the following:

.. code-block:: javascript

    [
        {
            "text": "John Doe",
            "firstname": "John",
            "lastname": "Doe",
            "extra": "whatever"
        },
        {
            "text": "123 Doe Street",
            "address": "123 Doe Street",
            "extra": "whatever"
        },
        {
            "text": "Doe",
            "name": "Doe",
            "extra": "whatever",
            "number": 42
        }
    ]

Multiple Serializers
--------------------

Alternatively, you can specify a 'serializers' attribute on your Meta class to use a different serializer class
for different indexes as show below:

.. code-block:: python

    class AggregateSearchSerializer(HaystackSerializer):
        class Meta:
            serializers = {
                PersonIndex: PersonSearchSerializer,
                PlaceIndex: PlaceSearchSerializer,
                ThingIndex: ThingSearchSerializer
            }

The ``serializers`` attribute is the important thing here, It's a dictionary with ``SearchIndex`` classes as
keys and ``Serializer`` classes as values.  Each result in the list of results from a search that contained
items from multiple indexes would be serialized according to the appropriate serializer.

.. warning::

    If a field name is shared across serializers, and one serializer overrides the field mapping, the overridden
    mapping will be used for *all* serializers. See the example below for more details.

.. code-block:: python

    from rest_framework import serializers

    class PersonSearchSerializer(HaystackSerializer):
        # NOTE: This override will be used for both Person and Place objects.
        name = serializers.SerializerMethodField()

        class Meta:
            fields = ['name']

    class PlaceSearchSerializer(HaystackSerializer):
        class Meta:
            fields = ['name']

    class AggregateSearchSerializer(HaystackSerializer):
        class Meta:
            serializers = {
                PersonIndex: PersonSearchSerializer,
                PlaceIndex: PlaceSearchSerializer,
                ThingIndex: ThingSearchSerializer
            }