From 747ff7a30b79e12d344169200de24f88a22ddee9 Mon Sep 17 00:00:00 2001 From: humbertotm Date: Mon, 28 May 2018 19:59:03 -0700 Subject: [PATCH] Fixed #29385 -- Made admindocs ModelDetailView show model properties. Original patch by bkaluza. Tests and docs by humbertotm. --- django/contrib/admindocs/views.py | 14 ++++++++++---- docs/ref/contrib/admin/admindocs.txt | 10 +++++++--- tests/admin_docs/models.py | 4 ++++ tests/admin_docs/test_views.py | 4 ++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 02449f7401..ac7cd11f1f 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -256,7 +256,7 @@ class ModelDetailView(BaseAdminDocsView): methods = [] # Gather model methods. for func_name, func in model.__dict__.items(): - if inspect.isfunction(func): + if inspect.isfunction(func) or isinstance(func, property): try: for exclude in MODEL_METHODS_EXCLUDE: if func_name.startswith(exclude): @@ -267,9 +267,15 @@ class ModelDetailView(BaseAdminDocsView): verbose = verbose and ( utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.model_name) ) - # If a method has no arguments, show it as a 'field', otherwise - # as a 'method with arguments'. - if func_has_no_args(func) and not func_accepts_kwargs(func) and not func_accepts_var_args(func): + # Show properties and methods without arguments as fields. + # Otherwise, show as a 'method with arguments'. + if isinstance(func, property): + fields.append({ + 'name': func_name, + 'data_type': get_return_data_type(func_name), + 'verbose': verbose or '' + }) + elif func_has_no_args(func) and not func_accepts_kwargs(func) and not func_accepts_var_args(func): fields.append({ 'name': func_name, 'data_type': get_return_data_type(func_name), diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt index e519bd8ed1..7779fe822a 100644 --- a/docs/ref/contrib/admin/admindocs.txt +++ b/docs/ref/contrib/admin/admindocs.txt @@ -51,9 +51,13 @@ Model reference =============== The **models** section of the ``admindocs`` page describes each model in the -system along with all the fields and methods available on it. Relationships -to other models appear as hyperlinks. Descriptions are pulled from ``help_text`` -attributes on fields or from docstrings on model methods. +system along with all the fields, properties, and methods available on it. +Relationships to other models appear as hyperlinks. Descriptions are pulled +from ``help_text`` attributes on fields or from docstrings on model methods. + +.. versionchanged:: 2.2 + + Older versions don't display model properties. A model with useful documentation might look like this:: diff --git a/tests/admin_docs/models.py b/tests/admin_docs/models.py index a425ae0fcd..02bf1efa9f 100644 --- a/tests/admin_docs/models.py +++ b/tests/admin_docs/models.py @@ -52,6 +52,10 @@ class Person(models.Model): def dummy_function(self, baz, rox, *some_args, **some_kwargs): return some_kwargs + @property + def a_property(self): + return 'a_property' + def suffix_company_name(self, suffix='ltd'): return self.company.name + suffix diff --git a/tests/admin_docs/test_views.py b/tests/admin_docs/test_views.py index c55891a3c0..05e1f6b329 100644 --- a/tests/admin_docs/test_views.py +++ b/tests/admin_docs/test_views.py @@ -208,6 +208,10 @@ class TestModelDetailView(TestDataMixin, AdminDocsTestCase): """ self.assertContains(self.response, "baz, rox, *some_args, **some_kwargs") + def test_instance_of_property_methods_are_displayed(self): + """Model properties are displayed as fields.""" + self.assertContains(self.response, 'a_property') + def test_method_data_types(self): company = Company.objects.create(name="Django") person = Person.objects.create(first_name="Human", last_name="User", company=company)