Browse Source

Search all Wagtail Page models (#501)

Jeremy Childers 2 years ago
parent
commit
2cc984bfd0

+ 0 - 12
coderedcms/models/page_models.py

@@ -107,18 +107,6 @@ def get_page_models():
 class CoderedPageMeta(PageBase):
     def __init__(cls, name, bases, dct):
         super().__init__(name, bases, dct)
-        if 'search_db_include' not in dct:
-            cls.search_db_include = False
-        if 'search_db_boost' not in dct:
-            cls.search_db_boost = 0
-        if 'search_filterable' not in dct:
-            cls.search_filterable = False
-        if 'search_name' not in dct:
-            cls.search_name = cls._meta.verbose_name
-        if 'search_name_plural' not in dct:
-            cls.search_name_plural = cls._meta.verbose_name_plural
-        if 'search_template' not in dct:
-            cls.search_template = 'coderedcms/pages/search_result.html'
         if not cls._meta.abstract:
             CODERED_PAGE_MODELS.append(cls)
 

+ 77 - 63
coderedcms/templates/coderedcms/pages/search.html

@@ -1,74 +1,88 @@
-{% extends "coderedcms/pages/web_page.html" %}
-{% load bootstrap4 i18n coderedcms_tags %}
+{% extends "coderedcms/pages/web_page_notitle.html" %}
+{% load bootstrap4 i18n coderedcms_tags wagtailcore_tags %}
 
-{% block title %}
-    {% if not form.s.value %}
-        {% trans 'Search' %}
-    {% else %}
-        {% trans 'Search for' %} “{{form.s.value}}”
-    {%endif%}
+{% wagtail_site as site %}
+
+{% block extra_head %}
+<title>{% if not form.s.value %}{% trans 'Search' %}{% else %}{% trans 'Search for' %} “{{form.s.value}}”{% endif %} — {{ site.site_name }}</title>
+{{ block.super }}
 {% endblock %}
 
-{% block content %}
-    <div class="container">
+{% block content_pre_body %}
+<div class="container my-5">
+  {% if not form.s.value %}
+  <h1>{% trans 'Search' %}</h1>
+  {% else %}
+  <h1>{% trans 'Search for' %} “{{form.s.value}}”</h1>
+  {% endif %}
+</div>
+{% endblock %}
 
-        <div class="mt-5">
-          {% if not form.s.value %}
-              <h2>{% trans 'Search' %}</h2>
-          {% else %}
-              <h2>{% trans 'Search for' %} “{{form.s.value}}”</h2>
-          {%endif%}
+{% block content_body %}
+<div class="container">
+  {% block search_form %}
+  {% if not settings.coderedcms.LayoutSettings.navbar_search %}
+  <form class="mt-5" action="{% url 'codered_search' %}" method="GET">
+    <div class="row">
+      <div class="col-sm-9">
+        {% bootstrap_form form size='large' layout='inline' %}
+      </div>
+      <div class="col-sm-3">
+        <div class="form-group">
+          <button class="btn btn-lg btn-block btn-outline-primary" type="submit">{% trans 'Search' %}</button>
         </div>
+      </div>
+    </div>
+  </form>
+  {% endif %}
+  {% endblock search_form %}
 
-        {% if not settings.coderedcms.LayoutSettings.navbar_search %}
-        <form class="mt-5" action="{% url 'codered_search' %}" method="GET">
-            <div class="row">
-                <div class="col-sm-9">
-                    {% bootstrap_form form size='large' layout='inline' %}
-                </div>
-                <div class="col-sm-3">
-                    <div class="form-group">
-                        <button class="btn btn-lg btn-block btn-outline-primary" type="submit">{% trans 'Search' %}</button>
-                    </div>
-                </div>
-            </div>
-        </form>
-        {% endif %}
+  {% block search_page_types %}
+  {% if pagetypes %}
+  {% query_update request.GET 'p' None as qs_nop %}
+  <div class="mt-5">
+    <ul class="nav nav-pills">
+      <li class="nav-item">
+        {% query_update qs_nop 't' None as qs_t %}
+        <a class="nav-link {% if not form.t.value %}active{% endif %}" href="?{{qs_t.urlencode}}">{% trans 'All Results' %}</a>
+      </li>
+      {% for pt in pagetypes %}
+      <li class="nav-item">
+        {% query_update qs_nop 't' pt.content_type.model as qs_t %}
+        <a class="nav-link {% if form.t.value == pt.content_type.model %}active{% endif %}" href="?{{qs_t.urlencode}}">{{pt|get_plural_name_of_class}}</a>
+      </li>
+      {% endfor %}
+    </ul>
+  </div>
+  {% endif %}
+  {% endblock search_page_types %}
 
-        {% if pagetypes %}
-        {% query_update request.GET 'p' None as qs_nop %}
-        <div class="mt-5">
-            <ul class="nav nav-pills">
-                <li class="nav-item">
-                    {% query_update qs_nop 't' None as qs_t %}
-                    <a class="nav-link {% if not form.t.value %}active{% endif %}" href="?{{qs_t.urlencode}}">{% trans 'All Results' %}</a>
-                </li>
-                {% for pt in pagetypes %}
-                <li class="nav-item">
-                    {% query_update qs_nop 't' pt.content_type.model as qs_t %}
-                    <a class="nav-link {% if form.t.value == pt.content_type.model %}active{% endif %}" href="?{{qs_t.urlencode}}">{{pt.search_name_plural}}</a>
-                </li>
-                {% endfor %}
-            </ul>
-        </div>
-        {% endif %}
+  <hr class="mb-5">
 
-        <hr class="mb-5">
+  {% if results_paginated.object_list %}
 
+  {% block search_results %}
+  {% for page in results_paginated %}
+  <div class="mb-5">
+    {% with page=page.specific %}
+    {% if page.search_template %}
+    {% include page.search_template %}
+    {% else %}
+    {% include 'coderedcms/pages/search_result.html' %}
+    {% endif %}
+    {% endwith %}
+  </div>
+  {% endfor %}
+  {% include "coderedcms/includes/pagination.html" with items=results_paginated %}
+  {% endblock search_results %}
 
-        {% if results_paginated.object_list %}
-            {% for page in results_paginated %}
-            <div class="mb-5">
-                {% with page=page.specific %}
-                    {% include page.search_template %}
-                {% endwith %}
-            </div>
-            {% endfor %}
-            {% include "coderedcms/includes/pagination.html" with items=results_paginated %}
-        {% else %}
-            {% if form.s.value %}
-              <p>{% trans 'No results found.' %}</p>
-            {% endif %}
-        {% endif %}
-    </div>
+  {% elif form.s.value %}
+
+  {% block search_noresults %}
+  <p>{% trans 'No results found.' %}</p>
+  {% endblock search_noresults %}
+
+  {% endif %}
+
+</div>
 {% endblock %}

+ 4 - 2
coderedcms/templates/coderedcms/pages/search_result.html

@@ -1,9 +1,11 @@
+{% load coderedcms_tags %}
+
 <div class="d-flex align-items-center">
     <h4><a href="{{page.url}}">{{page.title}}</a></h4>
-    {% if page.content_type.model_class in pagetypes %}<small class="ml-3 badge badge-secondary">{{page.search_name}}</small>{% endif %}
+    {% if page.content_type.model_class in pagetypes %}<small class="ml-3 badge badge-secondary">{{page|get_name_of_class}}</small>{% endif %}
 </div>
 {% if page.search_description %}
     <p>{{page.search_description|safe}}</p>
 {% elif page.body_preview %}
     <p>{{page.body_preview}}</p>
-{% endif %}
+{% endif %}

+ 26 - 0
coderedcms/templatetags/coderedcms_tags.py

@@ -184,3 +184,29 @@ def map_to_bootstrap_alert(message_tag):
         return message_to_alert_dict[message_tag]
     except KeyError:
         return ''
+
+
+@register.filter
+def get_name_of_class(class_type):
+    if hasattr(class_type.__class__, "search_name"):
+        return class_type.__class__.search_name
+    elif (
+            hasattr(class_type.__class__, "_meta") and
+            hasattr(class_type.__class__._meta, "verbose_name")
+    ):
+        return class_type.__class__._meta.verbose_name
+    else:
+        return class_type.__class__.__name__
+
+
+@register.filter
+def get_plural_name_of_class(class_type):
+    if hasattr(class_type.__class__, "search_name_plural"):
+        return class_type.__class__.search_name_plural
+    elif (
+            hasattr(class_type.__class__, "_meta") and
+            hasattr(class_type.__class__._meta, "verbose_name_plural")
+    ):
+        return class_type.__class__._meta.verbose_name_plural
+    else:
+        return class_type.__class__.__name__ + "s"

+ 18 - 46
coderedcms/views.py

@@ -1,6 +1,5 @@
 import mimetypes
 import os
-from itertools import chain
 from datetime import datetime
 from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect, JsonResponse
 from django.contrib.auth.decorators import login_required
@@ -11,19 +10,18 @@ from django.utils import timezone
 from django.utils.translation import ngettext, gettext_lazy as _
 from icalendar import Calendar
 from wagtail.admin import messages
-from wagtail.search.backends import db, get_search_backend
-from wagtail.search.models import Query
+from wagtail.core.models import Page, get_page_models
 from coderedcms import utils
 from coderedcms.forms import SearchForm
 from coderedcms.models import (
     CoderedPage,
     CoderedEventPage,
-    get_page_models,
     GeneralSettings,
     LayoutSettings
 )
 from coderedcms.importexport import convert_csv_to_json, import_pages, ImportPagesFromCSVFileForm
 from coderedcms.settings import crx_settings
+from coderedcms.templatetags.coderedcms_tags import get_name_of_class
 
 
 def search(request):
@@ -39,49 +37,26 @@ def search(request):
         search_query = search_form.cleaned_data['s']
         search_model = search_form.cleaned_data['t']
 
-        # get all codered models
-        pagemodels = sorted(get_page_models(), key=lambda k: k.search_name)
-        # get filterable models
+        # get all page models
+        pagemodels = sorted(get_page_models(), key=get_name_of_class)
+        # filter based on is search_filterable
         for model in pagemodels:
-            if model.search_filterable:
+            if hasattr(model, "search_filterable") and model.search_filterable:
                 pagetypes.append(model)
 
-        # get backend
-        backend = get_search_backend()
-
-        # DB search. Since this backend can't handle inheritance or scoring,
-        # search specified page types in the desired order and chain the results together.
-        # This provides better search results than simply searching limited fields on CoderedPage.
-        db_models = []
-        if backend.__class__ == db.SearchBackend:
-            for model in get_page_models():
-                if model.search_db_include:
-                    db_models.append(model)
-            db_models = sorted(db_models, reverse=True, key=lambda k: k.search_db_boost)
-
-        if backend.__class__ == db.SearchBackend and db_models:
-            for model in db_models:
-                # if search_model is provided, only search on that model
-                if not search_model or search_model == ContentType.objects.get_for_model(model).model:  # noqa
-                    curr_results = model.objects.live().search(search_query)
-                    if results:
-                        results = list(chain(results, curr_results))
-                    else:
-                        results = curr_results
-
-        # Fallback for any other search backend
-        else:
-            if search_model:
-                try:
-                    model = ContentType.objects.get(model=search_model).model_class()
-                    results = model.objects.live().search(search_query)
-                except ContentType.DoesNotExist:
-                    results = None
-            else:
-                results = CoderedPage.objects.live().order_by('-last_published_at').search(search_query)  # noqa
-
-        # paginate results
+        results = Page.objects.live()
+        if search_model:
+            try:
+                # If provided a model name, try to get it
+                model = ContentType.objects.get(model=search_model).model_class()
+                results = results.type(model)
+            except ContentType.DoesNotExist:
+                # Maintain existing behavior of only returning objects if the page type is real
+                results = None
+
+        # get and paginate results
         if results:
+            results = results.search(search_query)
             paginator = Paginator(results, GeneralSettings.for_request(request).search_num_results)
             page = request.GET.get('p', 1)
             try:
@@ -93,9 +68,6 @@ def search(request):
             except InvalidPage:
                 results_paginated = paginator.page(1)
 
-        # Log the query so Wagtail can suggest promoted results
-        Query.get(search_query).add_hit()
-
     # Render template
     return render(request, 'coderedcms/pages/search.html', {
         'request': request,

+ 7 - 1
docs/features/searching.rst

@@ -32,10 +32,16 @@ For example, to enable search filtering by Blog or by Products in addition to Al
 
 Would enable the following filter options on the search page: All Results, Blog, Products.
 
+
 Search fields
 -------------
 
-If using the Wagtail DatabaseSearch backend (default), only page Title and Search Description
+.. deprecated:: 0.25
+
+   The following behavior and the ``search_db_*`` options were removed in 0.25.
+   Use the `Wagtail search parameters <https://docs.wagtail.org/en/stable/reference/contrib/searchpromotions.html#module-wagtail.contrib.search_promotions>`_ instead.
+
+If using the ``wagtail.search.backends.db`` backend (removed in Wagtail 3.0), only page Title and Search Description
 fields are searched upon. This is due to a limitation in the DatabaseSearch backend;
 other backends such as PostgreSQL and Elasticsearch will search on additional specific fields
 such as body, article captions, etc. To enable more specific searching while still using the