Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow alphabetically sorted searches on the Django ORM backend #1

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion docs/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ You can enable this type of behavior by defining an ``autocomplete_create`` clas
Custom Search Field
===================

By default, the autocomplete widget will match input against the ``title`` field on your model. If you're using a model that doesn't have a ``title`` attribute, or you just want to search using a different field, you can customize which field it matches against by defining an ``autocomplete_search_field`` property on your model:
If your model is indexed using the native Wagtail `indexing methods <https://docs.wagtail.io/en/latest/topics/search/indexing.html>`_, then the configured backend will be used to search accross all indexed fields.
You can narrow the scope by setting the ``autocomplete_search_field`` on the model like in the example to only search one field.

If your model is not indexed then the native Django ORM is used to match input against the ``title`` field on your model.
If you're using a model that doesn't have a ``title`` attribute, or you just want to search using a different field, you can customize which field it matches against by defining an ``autocomplete_search_field`` property on your model:

.. code-block:: python

Expand All @@ -52,6 +56,12 @@ By default, the autocomplete widget will match input against the ``title`` field
MyModel.objects.filter(my_special_field__icontains='part')

Additionally, this means that ``autocomplete_search_field`` *must* be a model field and cannot be an arbitrary property or method.

To use a different lookup behaviour on the Django ORM you can specify a tuple with the lookup type on your model's autocomplete_search_field:

.. code-block:: python

autocomplete_search_field = ('my_special_field', 'istartswith')

Custom Label Display
====================
Expand Down
30 changes: 26 additions & 4 deletions wagtailautocomplete/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
from django.http import (HttpResponseBadRequest, HttpResponseForbidden,
JsonResponse)
from django.views.decorators.http import require_GET, require_POST
from wagtail import VERSION

if VERSION > (2, 0):
from wagtail.search.backends import get_search_backend
from wagtail.search.index import Indexed
else:
from wagtail.wagtailsearch.backends import get_search_backend
from wagtail.wagtailsearch.index import Indexed


def render_page(page):
Expand Down Expand Up @@ -64,10 +72,24 @@ def search(request):
except ValueError:
return HttpResponseBadRequest()

field_name = getattr(model, 'autocomplete_search_field', 'title')
filter_kwargs = dict()
filter_kwargs[field_name + '__icontains'] = search_query
queryset = model.objects.filter(**filter_kwargs)
field_name = getattr(model, 'autocomplete_search_field', None)
custom_lookup = isinstance(field_name, (list, tuple))
if not custom_lookup and issubclass(model, Indexed):
search_backend = get_search_backend()
if field_name:
queryset = search_backend.search(search_query, model, fields=[field_name])
else:
queryset = search_backend.search(search_query, model)
else:
lookup_type = 'icontains'
if custom_lookup:
lookup_type = field_name[1]
field_name = field_name[0]
field_name = field_name if field_name else 'title'
filter_kwargs = dict()
filter_kwargs["{0}__{1}".format(field_name, lookup_type)] = search_query
queryset = model.objects.filter(**filter_kwargs)


if getattr(queryset, 'live', None):
# Non-Page models like Snippets won't have a live/published status
Expand Down