summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsai-ganesh-03 <sandursaiganesh@gmail.com>2024-11-03 11:03:48 +0530
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-11-06 14:39:18 +0100
commitc2c544cf01107da158cb8c0c539555eafa0628db (patch)
treed3387e60d7e0e9f5a0c59648c31473fc2836567f
parent78c9a2703151432f8e35cb63fca5a566fee5f8ed (diff)
Fixed #27409 -- Made admindocs support custom link text in docstrings.
-rw-r--r--django/contrib/admindocs/utils.py20
-rw-r--r--docs/ref/contrib/admin/admindocs.txt9
-rw-r--r--docs/releases/5.2.txt5
-rw-r--r--tests/admin_docs/models.py10
-rw-r--r--tests/admin_docs/test_views.py19
5 files changed, 60 insertions, 3 deletions
diff --git a/django/contrib/admindocs/utils.py b/django/contrib/admindocs/utils.py
index 3a7ca4e781..5b28a8d2c6 100644
--- a/django/contrib/admindocs/utils.py
+++ b/django/contrib/admindocs/utils.py
@@ -99,6 +99,21 @@ ROLES = {
"tag": "%s/tags/#%s",
}
+explicit_title_re = re.compile(r"^(.+?)\s*(?<!\x00)<([^<]*?)>$", re.DOTALL)
+
+
+def split_explicit_title(text):
+ """
+ Split role content into title and target, if given.
+
+ From sphinx.util.nodes.split_explicit_title
+ See https://github.com/sphinx-doc/sphinx/blob/230ccf2/sphinx/util/nodes.py#L389
+ """
+ match = explicit_title_re.match(text)
+ if match:
+ return True, match.group(1), match.group(2)
+ return False, text, text
+
def create_reference_role(rolename, urlbase):
# Views and template names are case-sensitive.
@@ -107,14 +122,15 @@ def create_reference_role(rolename, urlbase):
def _role(name, rawtext, text, lineno, inliner, options=None, content=None):
if options is None:
options = {}
+ _, title, target = split_explicit_title(text)
node = docutils.nodes.reference(
rawtext,
- text,
+ title,
refuri=(
urlbase
% (
inliner.document.settings.link_base,
- text if is_case_sensitive else text.lower(),
+ target if is_case_sensitive else target.lower(),
)
),
**options,
diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt
index edc29b4a5c..240def8efb 100644
--- a/docs/ref/contrib/admin/admindocs.txt
+++ b/docs/ref/contrib/admin/admindocs.txt
@@ -31,6 +31,8 @@ Once those steps are complete, you can start browsing the documentation by
going to your admin interface and clicking the "Documentation" link in the
upper right of the page.
+.. _admindocs-helpers:
+
Documentation helpers
=====================
@@ -47,6 +49,13 @@ Template filters ``:filter:`filtername```
Templates ``:template:`path/to/template.html```
================= =======================
+Each of these support custom link text with the format
+``:role:`link text <link>```. For example, ``:tag:`block <built_in-block>```.
+
+.. versionchanged:: 5.2
+
+ Support for custom link text was added.
+
Model reference
===============
diff --git a/docs/releases/5.2.txt b/docs/releases/5.2.txt
index 8327de7405..d07e9cb098 100644
--- a/docs/releases/5.2.txt
+++ b/docs/releases/5.2.txt
@@ -44,7 +44,10 @@ Minor features
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* ...
+* Links to components in docstrings now supports custom link text, using the
+ format ``:role:`link text <link>```. See :ref:`documentation helpers
+ <admindocs-helpers>` for more details.
+
:mod:`django.contrib.auth`
~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/admin_docs/models.py b/tests/admin_docs/models.py
index b4ef84caba..4b52b4a4ea 100644
--- a/tests/admin_docs/models.py
+++ b/tests/admin_docs/models.py
@@ -15,6 +15,16 @@ class Group(models.Model):
class Family(models.Model):
+ """
+ Links with different link text.
+
+ This is a line with tag :tag:`extends <built_in-extends>`
+ This is a line with model :model:`Family <myapp.Family>`
+ This is a line with view :view:`Index <myapp.views.Index>`
+ This is a line with template :template:`index template <Index.html>`
+ This is a line with filter :filter:`example filter <filtername>`
+ """
+
last_name = models.CharField(max_length=200)
diff --git a/tests/admin_docs/test_views.py b/tests/admin_docs/test_views.py
index c48a89a1b0..f7232a7e03 100644
--- a/tests/admin_docs/test_views.py
+++ b/tests/admin_docs/test_views.py
@@ -441,6 +441,25 @@ class TestModelDetailView(TestDataMixin, AdminDocsTestCase):
self.assertContains(self.response, body, html=True)
self.assertContains(self.response, model_body, html=True)
+ def test_model_docstring_built_in_tag_links(self):
+ summary = "Links with different link text."
+ body = (
+ '<p>This is a line with tag <a class="reference external" '
+ 'href="/admindocs/tags/#built_in-extends">extends</a>\n'
+ 'This is a line with model <a class="reference external" '
+ 'href="/admindocs/models/myapp.family/">Family</a>\n'
+ 'This is a line with view <a class="reference external" '
+ 'href="/admindocs/views/myapp.views.Index/">Index</a>\n'
+ 'This is a line with template <a class="reference external" '
+ 'href="/admindocs/templates/Index.html/">index template</a>\n'
+ 'This is a line with filter <a class="reference external" '
+ 'href="/admindocs/filters/#filtername">example filter</a></p>'
+ )
+ url = reverse("django-admindocs-models-detail", args=["admin_docs", "family"])
+ response = self.client.get(url)
+ self.assertContains(response, summary, html=True)
+ self.assertContains(response, body, html=True)
+
def test_model_detail_title(self):
self.assertContains(self.response, "<h1>admin_docs.Person</h1>", html=True)