diff --git a/djangoproject/templates/404.html b/djangoproject/templates/404.html
index 885c594a3b..10d2eadecb 100644
--- a/djangoproject/templates/404.html
+++ b/djangoproject/templates/404.html
@@ -1,23 +1,51 @@
{% extends 'base_error.html' %}
{% load i18n %}
+{% load custom_tags %}
{% block title %}{% translate "Page not found" %}{% endblock %}
-{% block header %}
+
{% translate "We couldn’t find the page:" %}
+
"{{ broken_path }}"
+
+
+ {% blocktranslate trimmed %}
+ Looks like you followed a bad link. If you think it's our fault, please
+ let us know.
+ {% endblocktranslate %}
+
-
- {% blocktranslate trimmed %}
- Looks like you followed a bad link. If you think it's our fault, please
- let us know.
- {% endblocktranslate %}
+
+
+
+
- {% url 'homepage' as homepage_url %}
-
- {% blocktranslate trimmed %}
- Here's a link to the homepage. You know, just in case.
- {% endblocktranslate %}
+
+ {% if suggestions %}
+
{% translate "Did you mean?" %}
+
+ {% endif %}
+ {% url 'homepage' as homepage_url %}
+
+ {% blocktranslate trimmed %}
+ Here's a link to the homepage. You know, just in case.
+ {% endblocktranslate %}
+
+
{% endblock %}
diff --git a/docs/templatetags/docs.py b/docs/templatetags/docs.py
index 194a77e7f2..cdd5e597ee 100644
--- a/docs/templatetags/docs.py
+++ b/docs/templatetags/docs.py
@@ -1,4 +1,10 @@
+import difflib
+
from django import template
+from django.conf import settings
+from django.http import Http404
+from django.shortcuts import get_object_or_404
+from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.version import get_version_tuple
from pygments import highlight
@@ -11,18 +17,38 @@
register = template.Library()
+# List of existing docs URLs for similarity matching
+EXISTING_DOCS_URLS = [
+ "/en/4.2/ref/databases/",
+ "/en/4.2/ref/models/",
+ "/en/4.2/topics/db/",
+ "/en/4.2/howto/custom-model-fields/",
+ "/en/4.2/ref/settings/",
+ # Add more known URLs as needed
+]
+
+
+def get_suggestions(broken_url):
+ """Finds close matches for the broken URL using difflib."""
+ return difflib.get_close_matches(broken_url, EXISTING_DOCS_URLS, n=3, cutoff=0.6)
+
@register.inclusion_tag("docs/search_form.html", takes_context=True)
def search_form(context):
request = context["request"]
- release = DocumentRelease.objects.get_by_version_and_lang(
- context["version"],
- context["lang"],
- )
+ version = context.get("version", context.get("DJANGO_VERSION"))
+ lang = context.get("lang", context.get("LANGUAGE_CODE"))
+
+ release = get_object_or_404(DocumentRelease, version=version, lang=lang)
+ broken_path = request.path.replace(f"/{lang}/{version}/", "", 1)
+ suggestions = get_suggestions(f"/{broken_path}")
+
return {
"form": DocSearchForm(request.GET, release=release),
- "version": context["version"],
- "lang": context["lang"],
+ "version": version,
+ "lang": lang,
+ "suggestions": suggestions,
+ "broken_path": broken_path,
}