diff options
| author | Zan Anderle <zan.anderle@gmail.com> | 2014-11-03 20:16:28 +0100 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2014-11-03 15:30:46 -0500 |
| commit | 7b420367524ad9f29b8bf0284f4b40bd6cfc8b93 (patch) | |
| tree | 15e041668111d6e566684d480b3e72fcdd88a1c4 | |
| parent | 1cf109515a08aecb34c48bedb1df8027f7fad701 (diff) | |
Fixed #5405 -- Added admindocs support for reStructured text in model docstrings
Thanks elvard and gkmngrgn for work on the patch and Markus H. for review.
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/contrib/admindocs/templates/admin_doc/model_detail.html | 7 | ||||
| -rw-r--r-- | django/contrib/admindocs/views.py | 14 | ||||
| -rw-r--r-- | docs/releases/1.8.txt | 5 | ||||
| -rw-r--r-- | tests/admin_docs/models.py | 12 | ||||
| -rw-r--r-- | tests/admin_docs/tests.py | 107 |
6 files changed, 138 insertions, 8 deletions
@@ -701,6 +701,7 @@ answer newbie questions, and generally made Django that much better: Zach Thompson <zthompson47@gmail.com> Zain Memon Zak Johnson <zakj@nox.cx> + Žan Anderle <zan.anderle@gmail.com> Zbigniew Siciarz <zbigniew@siciarz.net> zegor Zlatko Mašek <zlatko.masek@gmail.com> diff --git a/django/contrib/admindocs/templates/admin_doc/model_detail.html b/django/contrib/admindocs/templates/admin_doc/model_detail.html index 77c8c2430c..59d8abcd8f 100644 --- a/django/contrib/admindocs/templates/admin_doc/model_detail.html +++ b/django/contrib/admindocs/templates/admin_doc/model_detail.html @@ -22,11 +22,10 @@ {% block content %} <div id="content-main"> -<h1>{{ summary }}</h1> +<h1>{{ name }}</h1> +<h2 class="subhead">{{ summary }}</h2> -{% if description %} - <p>{% filter linebreaksbr %}{% trans description %}{% endfilter %}</p> -{% endif %} +{{ description }} <div class="module"> <table class="model"> diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 6cd5df1e5c..f4a49431f6 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -178,18 +178,25 @@ class ModelDetailView(BaseAdminDocsView): template_name = 'admin_doc/model_detail.html' def get_context_data(self, **kwargs): + model_name = self.kwargs['model_name'] # Get the model class. try: app_config = apps.get_app_config(self.kwargs['app_label']) except LookupError: raise Http404(_("App %(app_label)r not found") % self.kwargs) try: - model = app_config.get_model(self.kwargs['model_name']) + model = app_config.get_model(model_name) except LookupError: raise Http404(_("Model %(model_name)r not found in app %(app_label)r") % self.kwargs) opts = model._meta + title, body, metadata = utils.parse_docstring(model.__doc__) + if title: + title = utils.parse_rst(title, 'model', _('model:') + model_name) + if body: + body = utils.parse_rst(body, 'model', _('model:') + model_name) + # Gather fields/field descriptions. fields = [] for field in opts.fields: @@ -271,9 +278,8 @@ class ModelDetailView(BaseAdminDocsView): }) kwargs.update({ 'name': '%s.%s' % (opts.app_label, opts.object_name), - # Translators: %s is an object type name - 'summary': _("Attributes on %s objects") % opts.object_name, - 'description': model.__doc__, + 'summary': title, + 'description': body, 'fields': fields, }) return super(ModelDetailView, self).get_context_data(**kwargs) diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index 875f17f40f..3cf7e77038 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -76,6 +76,11 @@ Minor features <django.contrib.admin.ModelAdmin.show_full_result_count>` to control whether or not the full count of objects should be displayed on a filtered admin page. +:mod:`django.contrib.admindocs` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* reStructuredText is now parsed in model docstrings. + :mod:`django.contrib.auth` ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/admin_docs/models.py b/tests/admin_docs/models.py index 9b8f388f4e..7e8b6c37e8 100644 --- a/tests/admin_docs/models.py +++ b/tests/admin_docs/models.py @@ -18,6 +18,18 @@ class Family(models.Model): class Person(models.Model): + """ + Stores information about a person, related to :model:`myapp.Company`. + + **Notes** + + Use ``save_changes()`` when saving this object. + + ``company`` + Field storing :model:`myapp.Company` where the person works. + + (DESCRIPTION) + """ first_name = models.CharField(max_length=200, help_text="The person's first name") last_name = models.CharField(max_length=200, help_text="The person's last name") company = models.ForeignKey(Company, help_text="place of work") diff --git a/tests/admin_docs/tests.py b/tests/admin_docs/tests.py index 6234834955..2b0f6dc065 100644 --- a/tests/admin_docs/tests.py +++ b/tests/admin_docs/tests.py @@ -291,3 +291,110 @@ class TestModelDetailView(AdminDocsTestCase): fields = response.context_data.get('fields') self.assertEqual(len(fields), 2) + + def test_model_docstring_renders_correctly(self): + summary = ( + '<h2 class="subhead"><p>Stores information about a person, related to <a class="reference external" ' + 'href="/admindocs/models/myapp.company/">myapp.Company</a>.</p></h2>' + ) + subheading = '<p><strong>Notes</strong></p>' + body = '<p>Use <tt class="docutils literal">save_changes()</tt> when saving this object.</p>' + model_body = ( + '<dl class="docutils"><dt><tt class="' + 'docutils literal">company</tt></dt><dd>Field storing <a class="' + 'reference external" href="/admindocs/models/myapp.company/">' + 'myapp.Company</a> where the person works.</dd></dl>' + ) + self.assertContains(self.response, 'DESCRIPTION') + self.assertContains(self.response, summary, html=True) + self.assertContains(self.response, subheading, html=True) + self.assertContains(self.response, body, html=True) + self.assertContains(self.response, model_body, html=True) + + +@unittest.skipUnless(utils.docutils_is_available, "no docutils installed.") +class TestUtils(AdminDocsTestCase): + """ + This __doc__ output is required for testing. I copied this example from + `admindocs` documentation. (TITLE) + + Display an individual :model:`myapp.MyModel`. + + **Context** + + ``RequestContext`` + + ``mymodel`` + An instance of :model:`myapp.MyModel`. + + **Template:** + + :template:`myapp/my_template.html` (DESCRIPTION) + + some_metadata: some data + + """ + + def setUp(self): + self.docstring = self.__doc__ + + def test_trim_docstring(self): + trim_docstring_output = utils.trim_docstring(self.docstring) + trimmed_docstring = ( + 'This __doc__ output is required for testing. I copied this ' + 'example from\n`admindocs` documentation. (TITLE)\n\n' + 'Display an individual :model:`myapp.MyModel`.\n\n' + '**Context**\n\n``RequestContext``\n\n``mymodel``\n' + ' An instance of :model:`myapp.MyModel`.\n\n' + '**Template:**\n\n:template:`myapp/my_template.html` ' + '(DESCRIPTION)\n\nsome_metadata: some data' + ) + self.assertEqual(trim_docstring_output, trimmed_docstring) + + def test_parse_docstring(self): + title, description, metadata = utils.parse_docstring(self.docstring) + docstring_title = ( + 'This __doc__ output is required for testing. I copied this example from\n' + '`admindocs` documentation. (TITLE)' + ) + docstring_description = ( + 'Display an individual :model:`myapp.MyModel`.\n\n' + '**Context**\n\n``RequestContext``\n\n``mymodel``\n' + ' An instance of :model:`myapp.MyModel`.\n\n' + '**Template:**\n\n:template:`myapp/my_template.html` ' + '(DESCRIPTION)' + ) + self.assertEqual(title, docstring_title) + self.assertEqual(description, docstring_description) + self.assertEqual(metadata, {'some_metadata': 'some data'}) + + def test_title_output(self): + title, description, metadata = utils.parse_docstring(self.docstring) + title_output = utils.parse_rst(title, 'model', 'model:admindocs') + self.assertIn('TITLE', title_output) + + title_rendered = ( + '<p>This __doc__ output is required for testing. I copied this ' + 'example from\n<a class="reference external" ' + 'href="/admindocs/models/admindocs/">admindocs</a> documentation. ' + '(TITLE)</p>\n' + ) + self.assertHTMLEqual(title_output, title_rendered) + + def test_description_output(self): + title, description, metadata = utils.parse_docstring(self.docstring) + description_output = utils.parse_rst(description, 'model', 'model:admindocs') + + description_rendered = ( + '<p>Display an individual <a class="reference external" ' + 'href="/admindocs/models/myapp.mymodel/">myapp.MyModel</a>.</p>\n' + '<p><strong>Context</strong></p>\n<p><tt class="docutils literal">' + 'RequestContext</tt></p>\n<dl class="docutils">\n<dt><tt class="' + 'docutils literal">mymodel</tt></dt>\n<dd>An instance of <a class="' + 'reference external" href="/admindocs/models/myapp.mymodel/">' + 'myapp.MyModel</a>.</dd>\n</dl>\n<p><strong>Template:</strong></p>' + '\n<p><a class="reference external" href="/admindocs/templates/' + 'myapp/my_template.html/">myapp/my_template.html</a> (DESCRIPTION)' + '</p>\n' + ) + self.assertHTMLEqual(description_output, description_rendered) |
