Compare commits
No commits in common. "653847df6a55fc03a0108d00bb930ebf81db9982" and "d75ea17b32e4d46334ea74abf7d05e772b78c9f2" have entirely different histories.
653847df6a
...
d75ea17b32
@ -7,7 +7,6 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|||||||
from modelcluster.contrib.taggit import ClusterTaggableManager
|
from modelcluster.contrib.taggit import ClusterTaggableManager
|
||||||
from modelcluster.fields import ParentalKey
|
from modelcluster.fields import ParentalKey
|
||||||
from taggit.models import TaggedItemBase
|
from taggit.models import TaggedItemBase
|
||||||
from wagtail.search import index
|
|
||||||
|
|
||||||
def _get_env_int(name, default):
|
def _get_env_int(name, default):
|
||||||
value = os.environ.get(name)
|
value = os.environ.get(name)
|
||||||
@ -273,12 +272,6 @@ class ArticlePage(Page):
|
|||||||
trending = models.BooleanField("Trending", default=False, help_text="在熱門區塊顯示")
|
trending = models.BooleanField("Trending", default=False, help_text="在熱門區塊顯示")
|
||||||
tags = ClusterTaggableManager(through="home.ArticlePageTag", blank=True)
|
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 + [
|
content_panels = Page.content_panels + [
|
||||||
FieldPanel("trending"),
|
FieldPanel("trending"),
|
||||||
FieldPanel("cover_image"),
|
FieldPanel("cover_image"),
|
||||||
@ -306,25 +299,3 @@ class ArticlePage(Page):
|
|||||||
|
|
||||||
context["related_articles"] = related_articles
|
context["related_articles"] = related_articles
|
||||||
return context
|
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))
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<span>Hashtags:</span>
|
<span>Hashtags:</span>
|
||||||
<ul>
|
<ul>
|
||||||
{% for tag in tags %}
|
{% for tag in tags %}
|
||||||
<li><a href="{% url 'hashtag_search' tag.slug %}">#{{ tag }}</a></li>
|
<li>#{{ tag }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load wagtailcore_tags %}
|
|
||||||
{% block content %}
|
|
||||||
<nav class="breadcrumbs" aria-label="breadcrumb">
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
{% if site_root %}
|
|
||||||
<a href="{{ site_root.url }}">首頁</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="/">首頁</a>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li><span>標籤</span></li>
|
|
||||||
<li><span>#{{ tag.name }}</span></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
{% include "home/includes/page-article-list.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
|
|
||||||
from taggit.models import Tag
|
|
||||||
from wagtail.models import Site
|
|
||||||
|
|
||||||
from .models import ArticlePage, PAGE_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
def hashtag_search(request, slug):
|
|
||||||
tag = get_object_or_404(Tag, slug=slug)
|
|
||||||
articles = (
|
|
||||||
ArticlePage.objects.live()
|
|
||||||
.filter(tags__slug=slug)
|
|
||||||
.order_by("-date")
|
|
||||||
)
|
|
||||||
|
|
||||||
paginator = Paginator(articles, PAGE_SIZE)
|
|
||||||
page_number = request.GET.get("page")
|
|
||||||
|
|
||||||
try:
|
|
||||||
page_obj = paginator.page(page_number)
|
|
||||||
except PageNotAnInteger:
|
|
||||||
page_obj = paginator.page(1)
|
|
||||||
except EmptyPage:
|
|
||||||
page_obj = paginator.page(paginator.num_pages)
|
|
||||||
|
|
||||||
site = Site.find_for_request(request)
|
|
||||||
site_root = site.root_page if site else None
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"tag": tag,
|
|
||||||
"category_sections": [
|
|
||||||
{
|
|
||||||
"title": f"#{tag.name}",
|
|
||||||
"items": page_obj,
|
|
||||||
"url": request.path,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"site_root": site_root,
|
|
||||||
"page": site_root.specific if site_root else None,
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, "home/hashtag_page.html", context)
|
|
||||||
@ -56,15 +56,5 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</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>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -7,14 +7,11 @@ from wagtail import urls as wagtail_urls
|
|||||||
from wagtail.documents import urls as wagtaildocs_urls
|
from wagtail.documents import urls as wagtaildocs_urls
|
||||||
|
|
||||||
from search import views as search_views
|
from search import views as search_views
|
||||||
from home import views as home_views
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("django-admin/", admin.site.urls),
|
path("django-admin/", admin.site.urls),
|
||||||
path("admin/", include(wagtailadmin_urls)),
|
path("admin/", include(wagtailadmin_urls)),
|
||||||
path("documents/", include(wagtaildocs_urls)),
|
path("documents/", include(wagtaildocs_urls)),
|
||||||
# use <str:slug> so Unicode tag slugs (e.g. 台北美食) still resolve
|
|
||||||
path("tags/<str:slug>/", home_views.hashtag_search, name="hashtag_search"),
|
|
||||||
path("search/", search_views.search, name="search"),
|
path("search/", search_views.search, name="search"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +1,38 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load wagtailcore_tags %}
|
{% load static wagtailcore_tags %}
|
||||||
|
|
||||||
{% block body_class %}template-searchresults{% endblock %}
|
{% block body_class %}template-searchresults{% endblock %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}Search{% endblock %}
|
||||||
{% if search_query %}搜尋:{{ search_query }}{% else %}搜尋{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<nav class="breadcrumbs" aria-label="breadcrumb">
|
<h1>Search</h1>
|
||||||
<ol>
|
|
||||||
|
<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 %}
|
||||||
<li>
|
<li>
|
||||||
{% if site_root %}
|
<h4><a href="{% pageurl result %}">{{ result }}</a></h4>
|
||||||
<a href="{{ site_root.url }}">首頁</a>
|
{% if result.search_description %}
|
||||||
{% else %}
|
{{ result.search_description }}
|
||||||
<a href="/">首頁</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li><span>搜尋</span></li>
|
{% endfor %}
|
||||||
{% if search_query %}
|
</ul>
|
||||||
<li><span>{{ search_query }}</span></li>
|
|
||||||
{% endif %}
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<section class="search-results">
|
{% if search_results.has_previous %}
|
||||||
{% if search_query %}
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.previous_page_number }}">Previous</a>
|
||||||
{% if results_count %}
|
{% endif %}
|
||||||
{% include "home/includes/page-article-list.html" %}
|
|
||||||
{% else %}
|
{% if search_results.has_next %}
|
||||||
<p>找不到與「{{ search_query }}」相關的文章。</p>
|
<a href="{% url 'search' %}?query={{ search_query|urlencode }}&page={{ search_results.next_page_number }}">Next</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% elif search_query %}
|
||||||
<p>請輸入關鍵字後再進行搜尋。</p>
|
No results found
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,48 +1,46 @@
|
|||||||
from urllib.parse import urlencode
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||||
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
|
||||||
from wagtail.models import Site
|
from wagtail.models import Page
|
||||||
|
|
||||||
from home.models import ArticlePage, PAGE_SIZE
|
# 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
|
||||||
|
|
||||||
|
|
||||||
def search(request):
|
def search(request):
|
||||||
search_query = (request.GET.get("query") or "").strip()
|
search_query = request.GET.get("query", None)
|
||||||
page_number = request.GET.get("page", 1)
|
page = request.GET.get("page", 1)
|
||||||
category_sections = []
|
|
||||||
results_page = None
|
|
||||||
results_count = 0
|
|
||||||
|
|
||||||
|
# Search
|
||||||
if search_query:
|
if search_query:
|
||||||
search_queryset = ArticlePage.objects.live().search(search_query)
|
search_results = Page.objects.live().search(search_query)
|
||||||
paginator = Paginator(search_queryset, PAGE_SIZE)
|
|
||||||
results_page = paginator.get_page(page_number)
|
|
||||||
results_count = paginator.count
|
|
||||||
|
|
||||||
if results_count:
|
# To log this query for use with the "Promoted search results" module:
|
||||||
query_string = urlencode({"query": search_query})
|
|
||||||
category_sections = [
|
|
||||||
{
|
|
||||||
"title": f"搜尋:{search_query}",
|
|
||||||
"items": results_page,
|
|
||||||
"url": f"{request.path}?{query_string}",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
site = Site.find_for_request(request)
|
# query = Query.get(search_query)
|
||||||
site_root = site.root_page if site else None
|
# 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)
|
||||||
|
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request,
|
request,
|
||||||
"search/search.html",
|
"search/search.html",
|
||||||
{
|
{
|
||||||
"search_query": search_query,
|
"search_query": search_query,
|
||||||
"category_sections": category_sections,
|
"search_results": search_results,
|
||||||
"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