Auto-documenting Django Models with Sphinx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
THIS_DIR = os.path.dirname(__file__)
PROJECT_DIR = os.path.join(THIS_DIR, 'relative/path/to/your/project/')
sys.path.append(PROJECT_DIR)

import inspect
import settings
from django.core.management import setup_environ
from django.utils.html import strip_tags
from django.utils,encoding import force_unicode

setup_environ(settings)


def process_docstring(app, what, name, obj, options, lines):
    # This causes import errors if left outside the function
    from django.db import models
    
    # Only look at objects that inherit from Django's base model class
    if inspect.isclass(obj) and issubclass(obj, models.Model):
        # Grab the field list from the meta class
        fields = obj._meta._fields()
    
        for field in fields:
            # Decode and strip any html out of the field's help text
            help_text = strip_tags(force_unicode(field.help_text))
            
            # Decode and capitalize the verbose name, for use if there isn't
            # any help text
            verbose_name = force_unicode(field.verbose_name).capitalize()
            
            if help_text:
                # Add the model field to the end of the docstring as a param
                # using the help text as the description
                lines.append(u':param %s: %s' % (field.attname, help_text))
            else:
                # Add the model field to the end of the docstring as a param
                # using the verbose name as the description
                lines.append(u':param %s: %s' % (field.attname, verbose_name))
                
            # Add the field's type to the docstring
            lines.append(u':type %s: %s' % (field.attname, type(field).__name__))
    
    # Return the extended docstring
    return lines  
  
def setup(app):
    # Register the docstring processor with sphinx
    app.connect('autodoc-process-docstring', process_docstring)  

More like this

  1. Sphinx Search ORM / Revised by ludo 6 years, 8 months ago
  2. SnippySnip by youell 5 years, 9 months ago
  3. Tuned IPAddressField with IPv4 & IPv6 support using Postgres Network Field type by illsci 4 years, 12 months ago
  4. django-mptt enabled FilteredSelectMultiple m2m widget by anentropic 4 years, 5 months ago
  5. Additional Change List Columns by sansmojo 6 years, 9 months ago

Comments

akaihola (on October 7, 2011):

This will fail if the help_text= kwargs for model fields are Unicode objects with non-ASCII characters, e.g.:

price = models.DecimalField(help_text=u'Price (in €)')

To fix this, add this import at the top:

from django.utils.encoding import force_unicode

and replace line 24 with:

help_text = strip_tags(force_unicode(field.help_text))

Also change the bytestrings on lines 33, 37 and 40 to Unicode literals, e.g. lines.append(u':param %s %s' ....

#

Voightkampff (on October 9, 2011):

Thanks for that! I've fixed the snippet.

#

vdboor (on July 9, 2012):

Thanks for the snippet! This works really sweet.

One addition to link to model classes to:

# Add the field's type to the docstring
if isinstance(field, models.ForeignKey):
    to = field.rel.to
    lines.append(u':type %s: %s to :class:`~%s.%s`' % (field.attname, type(field).__name__, to.__module__, to.__name__))
else:
    lines.append(u':type %s: %s' % (field.attname, type(field).__name__))

Secondly, it makes sense to keep the setup() in conf.py only, and place the rest in a docs/_ext folder. The Django docs do this, and it makes it really clean to implement.

#

(Forgotten your password?)