You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
3.9 KiB
136 lines
3.9 KiB
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())
|