Hi there all over the world. Today I#m gonna talk about fulltext-search implementation in Django with Haystack. (My actual search engine is whoosh, but i don’t think that matters for question).
As the build in forms from Haystack are not very pretty (AND in some parts in English, which i could not use for a german APP) , I simply tried to customize the build in forms of haystack to fullfill my needs.
After some struggeling, i managed it somehow. with ONE little issue left:
My class/styles properties to format the q field (Standard query field that comes with haystack-package) are only working on first page display. after submitting a search-query, the format jumps back to the haystack-basic for the q-field.
my views.py:
def search(request):
context = {}
context['form'] = MyModelSearchForm
return render(request, 'search/search.html', context)
so you see, nothing special.
my adapted haystack form:
from django import forms
from django.utils.encoding import smart_str
from django.utils.text import capfirst
from haystack import connections
from haystack.constants import DEFAULT_ALIAS
from haystack.query import SearchQuerySet
from haystack.utils import get_model_ct
from haystack.forms import SearchForm, EmptySearchQuerySet
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 MySearchForm(SearchForm):
q = forms.CharField(
required=False,
widget=forms.TextInput(attrs={
'class': "form-control rounded-start-2",
'placeholder': "Suchbegriff eingeben...",
"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 MyModelSearchForm(MySearchForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["models"] = forms.MultipleChoiceField(
choices=model_choices(),
required=False,
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())
and my template code for this part of page:
<div class="container-fluid d-grid justify-content-center bg-primary bg-gradient border-bottom border-dark pb-1">
<div class="input-group justify-content-center border border-1 rounded-2 border-dark mt-1">
{{ form.q }}
<button type="submit" value=" suchen" class="btn btn-primary">
<i class="fas fa-search"></i>
</button>
</div>
</div>
So on first toggling of page i see this:
…
after submitting a searchterm this:
I think, haystack is sending its basic properties to template form after submitting a query, but i can not identify the code passage where i would have to interact with to solve the problem…