Use serializer to validate search params
This commit is contained in:
parent
639f5885a4
commit
c4109e42f1
2 changed files with 43 additions and 25 deletions
|
@ -1,6 +1,7 @@
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
from django.core.paginator import EmptyPage, Paginator
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
from rest_framework import serializers
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
from wagtail.query import PageQuerySet
|
from wagtail.query import PageQuerySet
|
||||||
from wagtail.search.models import Query
|
from wagtail.search.models import Query
|
||||||
|
@ -19,6 +20,10 @@ class SearchPage(BaseContentMixin, BasePage): # type: ignore[misc]
|
||||||
search_fields = BasePage.search_fields + BaseContentMixin.search_fields
|
search_fields = BasePage.search_fields + BaseContentMixin.search_fields
|
||||||
PAGE_SIZE = 15
|
PAGE_SIZE = 15
|
||||||
|
|
||||||
|
class SearchParamsSerializer(serializers.Serializer):
|
||||||
|
q = serializers.CharField()
|
||||||
|
page = serializers.IntegerField(min_value=1, default=1)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def reading_time(self) -> int:
|
||||||
"""
|
"""
|
||||||
|
@ -35,29 +40,36 @@ class SearchPage(BaseContentMixin, BasePage): # type: ignore[misc]
|
||||||
|
|
||||||
def get_context(self, request: HttpRequest) -> dict:
|
def get_context(self, request: HttpRequest) -> dict:
|
||||||
context = super().get_context(request)
|
context = super().get_context(request)
|
||||||
if query_string := request.GET.get("q", ""):
|
|
||||||
filters, query = parse_query_string(query_string)
|
serializer = self.SearchParamsSerializer(data=request.GET)
|
||||||
Query.get(query_string).add_hit()
|
|
||||||
|
if serializer.is_valid():
|
||||||
|
search_query = serializer.validated_data["q"]
|
||||||
|
filters, query = parse_query_string(search_query)
|
||||||
|
Query.get(search_query).add_hit()
|
||||||
pages = self.get_search_pages().search(query)
|
pages = self.get_search_pages().search(query)
|
||||||
|
|
||||||
|
paginator = Paginator(pages, self.PAGE_SIZE)
|
||||||
|
context["paginator"] = paginator
|
||||||
|
page_num = serializer.validated_data["page"]
|
||||||
|
context["page_num"] = page_num
|
||||||
|
try:
|
||||||
|
results = paginator.page(page_num)
|
||||||
|
|
||||||
|
# HACK: Search results aren't a queryset, so we can't call `.specific` on it. This forces it to one as efficiently as possible
|
||||||
|
if not isinstance(results.object_list, PageQuerySet):
|
||||||
|
results.object_list = Page.objects.filter(
|
||||||
|
id__in=list(
|
||||||
|
results.object_list.get_queryset().values_list(
|
||||||
|
"id", flat=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).specific()
|
||||||
|
except EmptyPage:
|
||||||
|
results = []
|
||||||
|
|
||||||
|
context["results"] = results
|
||||||
else:
|
else:
|
||||||
pages = Page.objects.none()
|
context["invalid_search"] = True
|
||||||
|
|
||||||
paginator = Paginator(pages, self.PAGE_SIZE)
|
|
||||||
page_num = request.GET.get("page", "1")
|
|
||||||
try:
|
|
||||||
results = paginator.page(page_num)
|
|
||||||
|
|
||||||
# HACK: Search results aren't a queryset, so we can't call `.specific` on it. This forces it to one as efficiently as possible
|
|
||||||
if not isinstance(results.object_list, PageQuerySet):
|
|
||||||
results.object_list = Page.objects.filter(
|
|
||||||
id__in=list(
|
|
||||||
results.object_list.get_queryset().values_list("id", flat=True)
|
|
||||||
)
|
|
||||||
).specific()
|
|
||||||
except (PageNotAnInteger, EmptyPage):
|
|
||||||
results = None
|
|
||||||
context["invalid_page"] = True
|
|
||||||
|
|
||||||
context["results"] = results
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -11,8 +11,14 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<section class="container">
|
<section class="container">
|
||||||
{% if invalid_page %}
|
{% if invalid_search %}
|
||||||
<p>Invalid page</p>
|
<p>Invalid search</p>
|
||||||
|
{% elif results|length == 0 %}
|
||||||
|
{% if page_num > paginator.num_pages %}
|
||||||
|
<p>There aren't {{ page_num }} page - only {{ paginator.num_pages }}.</p>
|
||||||
|
{% else %}
|
||||||
|
<p>No results</p>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for page in results %}
|
{% for page in results %}
|
||||||
{% include "common/listing-item.html" %}
|
{% include "common/listing-item.html" %}
|
||||||
|
|
Loading…
Reference in a new issue