Fixed #29385 -- Made admindocs ModelDetailView show model properties.

Original patch by bkaluza. Tests and docs by humbertotm.
This commit is contained in:
humbertotm 2018-05-28 19:59:03 -07:00 committed by Tim Graham
parent 085ebc5f1a
commit 747ff7a30b
4 changed files with 25 additions and 7 deletions

View File

@ -256,7 +256,7 @@ class ModelDetailView(BaseAdminDocsView):
methods = [] methods = []
# Gather model methods. # Gather model methods.
for func_name, func in model.__dict__.items(): for func_name, func in model.__dict__.items():
if inspect.isfunction(func): if inspect.isfunction(func) or isinstance(func, property):
try: try:
for exclude in MODEL_METHODS_EXCLUDE: for exclude in MODEL_METHODS_EXCLUDE:
if func_name.startswith(exclude): if func_name.startswith(exclude):
@ -267,9 +267,15 @@ class ModelDetailView(BaseAdminDocsView):
verbose = verbose and ( verbose = verbose and (
utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.model_name) utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.model_name)
) )
# If a method has no arguments, show it as a 'field', otherwise # Show properties and methods without arguments as fields.
# as a 'method with arguments'. # Otherwise, show as a 'method with arguments'.
if func_has_no_args(func) and not func_accepts_kwargs(func) and not func_accepts_var_args(func): 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({ fields.append({
'name': func_name, 'name': func_name,
'data_type': get_return_data_type(func_name), 'data_type': get_return_data_type(func_name),

View File

@ -51,9 +51,13 @@ Model reference
=============== ===============
The **models** section of the ``admindocs`` page describes each model in the The **models** section of the ``admindocs`` page describes each model in the
system along with all the fields and methods available on it. Relationships system along with all the fields, properties, and methods available on it.
to other models appear as hyperlinks. Descriptions are pulled from ``help_text`` Relationships to other models appear as hyperlinks. Descriptions are pulled
attributes on fields or from docstrings on model methods. 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:: A model with useful documentation might look like this::

View File

@ -52,6 +52,10 @@ class Person(models.Model):
def dummy_function(self, baz, rox, *some_args, **some_kwargs): def dummy_function(self, baz, rox, *some_args, **some_kwargs):
return some_kwargs return some_kwargs
@property
def a_property(self):
return 'a_property'
def suffix_company_name(self, suffix='ltd'): def suffix_company_name(self, suffix='ltd'):
return self.company.name + suffix return self.company.name + suffix

View File

@ -208,6 +208,10 @@ class TestModelDetailView(TestDataMixin, AdminDocsTestCase):
""" """
self.assertContains(self.response, "<td>baz, rox, *some_args, **some_kwargs</td>") self.assertContains(self.response, "<td>baz, rox, *some_args, **some_kwargs</td>")
def test_instance_of_property_methods_are_displayed(self):
"""Model properties are displayed as fields."""
self.assertContains(self.response, '<td>a_property</td>')
def test_method_data_types(self): def test_method_data_types(self):
company = Company.objects.create(name="Django") company = Company.objects.create(name="Django")
person = Person.objects.create(first_name="Human", last_name="User", company=company) person = Person.objects.create(first_name="Human", last_name="User", company=company)