Add search functionality to ArticlePage and enhance search templates
- Implement search fields in ArticlePage model for indexing. - Update hashtag search view to include site root in context. - Enhance header with a search form for articles. - Modify search results template to improve user experience and display.
This commit is contained in:
parent
a98d36da14
commit
653847df6a
@ -7,6 +7,7 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from modelcluster.contrib.taggit import ClusterTaggableManager
|
||||
from modelcluster.fields import ParentalKey
|
||||
from taggit.models import TaggedItemBase
|
||||
from wagtail.search import index
|
||||
|
||||
def _get_env_int(name, default):
|
||||
value = os.environ.get(name)
|
||||
@ -272,6 +273,12 @@ class ArticlePage(Page):
|
||||
trending = models.BooleanField("Trending", default=False, help_text="在熱門區塊顯示")
|
||||
tags = ClusterTaggableManager(through="home.ArticlePageTag", blank=True)
|
||||
|
||||
search_fields = Page.search_fields + [
|
||||
index.SearchField("intro", partial_match=True),
|
||||
index.SearchField("body_search_text", partial_match=True),
|
||||
index.SearchField("tag_names_search_text", partial_match=True),
|
||||
]
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel("trending"),
|
||||
FieldPanel("cover_image"),
|
||||
@ -299,3 +306,25 @@ class ArticlePage(Page):
|
||||
|
||||
context["related_articles"] = related_articles
|
||||
return context
|
||||
|
||||
@property
|
||||
def body_search_text(self):
|
||||
if not self.body:
|
||||
return ""
|
||||
|
||||
excluded_types = {"image", "embed", "hr", "html"}
|
||||
chunks = []
|
||||
|
||||
for block in self.body:
|
||||
if block.block_type in excluded_types:
|
||||
continue
|
||||
# Each block decides how to expose searchable text
|
||||
block_content = block.block.get_searchable_content(block.value)
|
||||
if block_content:
|
||||
chunks.extend(block_content)
|
||||
|
||||
return " ".join(text for text in chunks if isinstance(text, str))
|
||||
|
||||
@property
|
||||
def tag_names_search_text(self):
|
||||
return " ".join(self.tags.values_list("name", flat=True))
|
||||
|
||||
@ -38,6 +38,7 @@ def hashtag_search(request, slug):
|
||||
}
|
||||
],
|
||||
"site_root": site_root,
|
||||
"page": site_root.specific if site_root else None,
|
||||
}
|
||||
|
||||
return render(request, "home/hashtag_page.html", context)
|
||||
|
||||
@ -56,5 +56,15 @@
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<form class="header-search" action="{% url 'search' %}" method="get" role="search">
|
||||
<input
|
||||
type="search"
|
||||
name="query"
|
||||
placeholder="搜尋文章"
|
||||
value="{{ request.GET.query|default:'' }}"
|
||||
aria-label="搜尋文章">
|
||||
<button type="submit">搜尋</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -1,38 +1,38 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static wagtailcore_tags %}
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
{% block body_class %}template-searchresults{% endblock %}
|
||||
|
||||
{% block title %}Search{% endblock %}
|
||||
{% block title %}
|
||||
{% if search_query %}搜尋:{{ search_query }}{% else %}搜尋{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Search</h1>
|
||||
|
||||
<form action="{% url 'search' %}" method="get">
|
||||
<input type="text" name="query"{% if search_query %} value="{{ search_query }}"{% endif %}>
|
||||
<input type="submit" value="Search" class="button">
|
||||
</form>
|
||||
|
||||
{% if search_results %}
|
||||
<ul>
|
||||
{% for result in search_results %}
|
||||
<nav class="breadcrumbs" aria-label="breadcrumb">
|
||||
<ol>
|
||||
<li>
|
||||
<h4><a href="{% pageurl result %}">{{ result }}</a></h4>
|
||||
{% if result.search_description %}
|
||||
{{ result.search_description }}
|
||||
{% if site_root %}
|
||||
<a href="{{ site_root.url }}">首頁</a>
|
||||
{% else %}
|
||||
<a href="/">首頁</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<li><span>搜尋</span></li>
|
||||
{% if search_query %}
|
||||
<li><span>{{ search_query }}</span></li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if search_results.has_previous %}
|
||||
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.previous_page_number }}">Previous</a>
|
||||
{% endif %}
|
||||
|
||||
{% if search_results.has_next %}
|
||||
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.next_page_number }}">Next</a>
|
||||
{% endif %}
|
||||
{% elif search_query %}
|
||||
No results found
|
||||
{% endif %}
|
||||
<section class="search-results">
|
||||
{% if search_query %}
|
||||
{% if results_count %}
|
||||
{% include "home/includes/page-article-list.html" %}
|
||||
{% else %}
|
||||
<p>找不到與「{{ search_query }}」相關的文章。</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>請輸入關鍵字後再進行搜尋。</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,46 +1,48 @@
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from django.core.paginator import Paginator
|
||||
from django.template.response import TemplateResponse
|
||||
|
||||
from wagtail.models import Page
|
||||
from wagtail.models import Site
|
||||
|
||||
# To enable logging of search queries for use with the "Promoted search results" module
|
||||
# <https://docs.wagtail.org/en/stable/reference/contrib/searchpromotions.html>
|
||||
# uncomment the following line and the lines indicated in the search function
|
||||
# (after adding wagtail.contrib.search_promotions to INSTALLED_APPS):
|
||||
|
||||
# from wagtail.contrib.search_promotions.models import Query
|
||||
from home.models import ArticlePage, PAGE_SIZE
|
||||
|
||||
|
||||
def search(request):
|
||||
search_query = request.GET.get("query", None)
|
||||
page = request.GET.get("page", 1)
|
||||
search_query = (request.GET.get("query") or "").strip()
|
||||
page_number = request.GET.get("page", 1)
|
||||
category_sections = []
|
||||
results_page = None
|
||||
results_count = 0
|
||||
|
||||
# Search
|
||||
if search_query:
|
||||
search_results = Page.objects.live().search(search_query)
|
||||
search_queryset = ArticlePage.objects.live().search(search_query)
|
||||
paginator = Paginator(search_queryset, PAGE_SIZE)
|
||||
results_page = paginator.get_page(page_number)
|
||||
results_count = paginator.count
|
||||
|
||||
# To log this query for use with the "Promoted search results" module:
|
||||
if results_count:
|
||||
query_string = urlencode({"query": search_query})
|
||||
category_sections = [
|
||||
{
|
||||
"title": f"搜尋:{search_query}",
|
||||
"items": results_page,
|
||||
"url": f"{request.path}?{query_string}",
|
||||
}
|
||||
]
|
||||
|
||||
# query = Query.get(search_query)
|
||||
# query.add_hit()
|
||||
|
||||
else:
|
||||
search_results = Page.objects.none()
|
||||
|
||||
# Pagination
|
||||
paginator = Paginator(search_results, 10)
|
||||
try:
|
||||
search_results = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
search_results = paginator.page(1)
|
||||
except EmptyPage:
|
||||
search_results = paginator.page(paginator.num_pages)
|
||||
site = Site.find_for_request(request)
|
||||
site_root = site.root_page if site else None
|
||||
|
||||
return TemplateResponse(
|
||||
request,
|
||||
"search/search.html",
|
||||
{
|
||||
"search_query": search_query,
|
||||
"search_results": search_results,
|
||||
"category_sections": category_sections,
|
||||
"results_page": results_page,
|
||||
"results_count": results_count,
|
||||
"site_root": site_root,
|
||||
"page": site_root.specific if site_root else None,
|
||||
},
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user