Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Sphinx add-on to annotate Django models based on fields and their help_text. Based on https://djangosnippets.org/snippets/2533/ - but adds ForeignKey resolution, and ensure field.rel.to is an actual model instead of a string.
import sys, os
local_path = lambda path: os.path.join(os.path.dirname(__file__), path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'PROJECTNAME.settings'
sys.path.append(local_path('..'))
... # Rest of conf.py goes here
def setup(app):
from django_sphinx import process_docstring
# Register the docstring processor with sphinx
app.connect('autodoc-process-docstring', process_docstring)
import inspect
from django.utils.html import strip_tags
from django.utils.encoding import force_unicode
def process_docstring(app, what, name, obj, options, lines):
# This causes import errors if left outside the function
from django.db import models
# Make sure we have loaded models, otherwise related fields may end up
# as strings
models.get_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
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__))
# Return the extended docstring
return lines
@eshandas

This comment has been minimized.

Copy link

@eshandas eshandas commented Sep 22, 2017

Hello,

The above snippet doesn't seem to be working for Django 1.11. It throws the following error upon executing "make html". Please note that the app is listed in INSTALLED_APPS and also has apps.py.

WARNING: autodoc: failed to import module u'rule_engine.core.nodes'; the following exception was raised:
Traceback (most recent call last):
  File "/home/yml/.virtualenvs/loyalty/local/lib/python2.7/site-packages/sphinx/ext/autodoc.py", line 551, in import_object
    __import__(self.modname)
  File "/home/yml/Documents/Projects/LoyaltyProgram/loyalty/rule_engine/core/nodes.py", line 9, in <module>
    from rule_engine.rules.validations import (
  File "/home/yml/Documents/Projects/LoyaltyProgram/loyalty/rule_engine/rules/validations.py", line 1, in <module>
    from events.models import (
  File "/home/yml/Documents/Projects/LoyaltyProgram/loyalty/events/models.py", line 6, in <module>
    from companies.models import Company
  File "/home/yml/Documents/Projects/LoyaltyProgram/loyalty/companies/models.py", line 9, in <module>
    class Company(models.Model):
  File "/home/yml/.virtualenvs/loyalty/local/lib/python2.7/site-packages/django/db/models/base.py", line 118, in __new__
    "INSTALLED_APPS." % (module, name)
RuntimeError: Model class companies.models.Company doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

The Sphinx conf.py looks like this:

django.setup()

def process_docstring(app, what, name, obj, options, lines):
    ...

def setup(app):
    # Register the docstring processor with sphinx
    app.connect('autodoc-process-docstring', process_docstring)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.