/
indexes.py
72 lines (57 loc) · 2.61 KB
/
indexes.py
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
from django.core.exceptions import ImproperlyConfigured
from haystack import indexes
class BaseSearchIndex(indexes.SearchIndex):
"""Base class for a search index.
This sets up a few common fields we want all indexes to include.
"""
#: The model to index.
model = None
#: The local site attribute on the model.
#:
#: For ForeignKeys, this should be the name of the ID field, as in
#: 'local_site_id'. For ManyToManyFields, it should be the standard field
#: name.
local_site_attr = None
# Common fields for all search indexes.
text = indexes.CharField(document=True, use_template=True)
local_sites = indexes.MultiValueField(null=True)
NO_LOCAL_SITE_ID = 0
def get_model(self):
"""Return the model for this index."""
return self.model
def prepare_local_sites(self, obj):
"""Prepare the list of local sites for the search index.
This will take any associated local sites on the object and store
them in the index as a list. The search view can then easily look up
values in the list, regardless of the type of object.
If the object is not a part of a local site, the list will be
``[0]``, indicating no local site.
"""
if not self.local_site_attr:
raise ImproperlyConfigured('local_site_attr must be set on %r'
% self.__class__)
if not hasattr(obj, self.local_site_attr):
raise ImproperlyConfigured(
'"%s" is not a valid local site attribute on %r'
% (self.local_site_attr, obj.__class__))
local_sites = getattr(obj, self.local_site_attr, None)
if self.local_site_attr.endswith('_id'):
# This is from a ForeignKey. We're working with a numeric ID.
if local_sites is not None:
results = [local_sites]
else:
results = [self.NO_LOCAL_SITE_ID]
else:
# This is most likely a ManyToManyField. Anything else is an
# error.
#
# We want to loop through the actual entries and not the primary
# keys. The caller is responsible for doing a prefetch_related().
results = [
local_site.pk
for local_site in local_sites.all()
] or [self.NO_LOCAL_SITE_ID]
# Convert these all to strings. This is what MultiValueField would
# normally do if we didn't prepare it, and is needed for the kinds of
# comparisons we perform when using Elasticsearch 7.x+.
return [str(_pk) for _pk in results]