diff --git a/djangoproject/scss/_style.scss b/djangoproject/scss/_style.scss
index 73edaa276..f6baff1d3 100644
--- a/djangoproject/scss/_style.scss
+++ b/djangoproject/scss/_style.scss
@@ -2578,6 +2578,40 @@ table.docutils th {
}
}
+search.filters {
+ @include sans-serif;
+
+ display: flex;
+ gap: 10px;
+ border-bottom: 2px solid var(--hairline-color);
+ overflow-x: auto;
+ white-space: nowrap;
+ padding-bottom: 0;
+ position: relative;
+
+ a {
+ padding: 10px 20px;
+ text-decoration: none;
+ border-bottom: 3px solid transparent;
+ transition: color 0.3s ease, border-bottom 0.3s ease;
+ color: var(--text-light);
+ flex-shrink: 0;
+
+ &:not([href]) {
+ color: var(--body-fg);
+ font-weight: bold;
+ border-bottom: 3px solid var(--primary);
+ }
+
+ &[href]:focus,
+ &[href]:active,
+ &[href]:hover {
+ outline: none;
+ border-bottom: 3px solid var(--hairline-color);
+ }
+ }
+}
+
.search-links {
@extend .list-links;
diff --git a/docs/models.py b/docs/models.py
index 8ff9a50f7..fb6714b9b 100644
--- a/docs/models.py
+++ b/docs/models.py
@@ -254,7 +254,7 @@ def breadcrumbs(self, document):
else:
return self.none()
- def search(self, query_text, release):
+ def search(self, query_text, release, document_category=None):
"""Use full-text search to return documents matching query_text."""
query_text = query_text.strip()
if query_text:
@@ -268,9 +268,12 @@ def search(self, query_text, release):
stop_sel=STOP_SEL,
config=models.F("config"),
)
+ base_filter = Q(release_id=release.id)
+ if document_category:
+ base_filter &= Q(metadata__parents__startswith=document_category)
base_qs = (
self.select_related("release__release")
- .filter(release_id=release.id)
+ .filter(base_filter)
.annotate(
headline=search("title", search_query),
highlight=search(
diff --git a/docs/search.py b/docs/search.py
index 06ce3a960..1a2ebcaa7 100644
--- a/docs/search.py
+++ b/docs/search.py
@@ -1,6 +1,7 @@
from django.contrib.postgres.search import SearchVector
-from django.db.models import F
+from django.db.models import F, TextChoices
from django.db.models.fields.json import KeyTextTransform
+from django.utils.translation import gettext_lazy as _
# Imported from
# https://github.com/postgres/postgres/blob/REL_14_STABLE/src/bin/initdb/initdb.c#L659
@@ -51,3 +52,23 @@
START_SEL = ""
STOP_SEL = ""
+
+
+class DocumentationCategory(TextChoices):
+ """
+ Categories used to filter the documentation search.
+ The value must match a folder name within django/docs.
+ """
+
+ # Diátaxis folders.
+ REFERENCE = "ref", _("API Reference")
+ TOPICS = "topics", _("Using Django")
+ HOWTO = "howto", _("How-to guides")
+ RELEASE_NOTES = "releases", _("Release notes")
+
+ @classmethod
+ def parse(cls, value, default=None):
+ try:
+ return cls(value)
+ except ValueError:
+ return None
diff --git a/docs/templates/docs/search_form.html b/docs/templates/docs/search_form.html
index 7c44d75d6..65823c757 100644
--- a/docs/templates/docs/search_form.html
+++ b/docs/templates/docs/search_form.html
@@ -1,11 +1,12 @@
{% load i18n %}
+
+ {% querystring category=None page=None as all_search %} + {% blocktranslate trimmed %}Please try searching all documentation results.{% endblocktranslate %} +
+