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
|
from django import forms
from django.utils.encoding import smart_str
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _
from haystack import connections
from haystack.constants import DEFAULT_ALIAS
from haystack.query import EmptySearchQuerySet, SearchQuerySet
from haystack.utils import get_model_ct
from haystack.utils.app_loading import haystack_get_model
def model_choices(using=DEFAULT_ALIAS):
choices = [
(get_model_ct(m), capfirst(smart_str(m._meta.verbose_name_plural)))
for m in connections[using].get_unified_index().get_indexed_models()
]
return sorted(choices, key=lambda x: x[1])
class SearchForm(forms.Form):
q = forms.CharField(
required=False,
label=_("Search"),
widget=forms.TextInput(attrs={"type": "search"}),
)
def __init__(self, *args, **kwargs):
self.searchqueryset = kwargs.pop("searchqueryset", None)
self.load_all = kwargs.pop("load_all", False)
if self.searchqueryset is None:
self.searchqueryset = SearchQuerySet()
super().__init__(*args, **kwargs)
def no_query_found(self):
"""
Determines the behavior when no query was found.
By default, no results are returned (``EmptySearchQuerySet``).
Should you want to show all results, override this method in your
own ``SearchForm`` subclass and do ``return self.searchqueryset.all()``.
"""
return EmptySearchQuerySet()
def search(self):
if not self.is_valid():
return self.no_query_found()
if not self.cleaned_data.get("q"):
return self.no_query_found()
sqs = self.searchqueryset.auto_query(self.cleaned_data["q"])
if self.load_all:
sqs = sqs.load_all()
return sqs
def get_suggestion(self):
if not self.is_valid():
return None
return self.searchqueryset.spelling_suggestion(self.cleaned_data["q"])
class HighlightedSearchForm(SearchForm):
def search(self):
return super().search().highlight()
class FacetedSearchForm(SearchForm):
def __init__(self, *args, **kwargs):
self.selected_facets = kwargs.pop("selected_facets", [])
super().__init__(*args, **kwargs)
def search(self):
sqs = super().search()
# We need to process each facet to ensure that the field name and the
# value are quoted correctly and separately:
for facet in self.selected_facets:
if ":" not in facet:
continue
field, value = facet.split(":", 1)
if value:
sqs = sqs.narrow('%s:"%s"' % (field, sqs.query.clean(value)))
return sqs
class ModelSearchForm(SearchForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["models"] = forms.MultipleChoiceField(
choices=model_choices(),
required=False,
label=_("Search In"),
widget=forms.CheckboxSelectMultiple,
)
def get_models(self):
"""Return a list of the selected models."""
search_models = []
if self.is_valid():
for model in self.cleaned_data["models"]:
search_models.append(haystack_get_model(*model.split(".")))
return search_models
def search(self):
sqs = super().search()
return sqs.models(*self.get_models())
class HighlightedModelSearchForm(ModelSearchForm):
def search(self):
return super().search().highlight()
class FacetedModelSearchForm(ModelSearchForm):
selected_facets = forms.CharField(required=False, widget=forms.HiddenInput)
def search(self):
sqs = super().search()
if hasattr(self, "cleaned_data") and self.cleaned_data["selected_facets"]:
sqs = sqs.narrow(self.cleaned_data["selected_facets"])
return sqs.models(*self.get_models())
|