- Author:
- Voightkampff
- Posted:
- August 25, 2011
- Language:
- Python
- Version:
- 1.3
- Score:
- 5 (after 5 ratings)
In my sphinx documentation I really wanted a nice clean list of the fields on my Django models. The most obvious way of doing this is to add ":param blah:" tags to the docstring, but this takes a long time to implement and violates DRY principles when you already have lots of nice help text in the model definition. Another way is to use "#:" comments on attributes, but this approach suffers from the same issues as the previous method with the additional problem of Sphinx crapping out on file and custom fields.
So anyway, this is my solution. It uses the Sphinx docstring processing callback to intercept any objects that inherit from django.models.Model and creates a nice param list of all the fields on that model. Param descriptions come from the field's help text or verbose name if no help text is defined.
To use this, just add it to the end of your source/conf.py, filling out the project path as appropriate. You may be able to skip the Django environment setup lines if you're adding this to a Sphinx doc that already has Django models set up.
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
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
This will fail if the
help_text=
kwargs for model fields are Unicode objects with non-ASCII characters, e.g.:To fix this, add this import at the top:
and replace line 24 with:
Also change the bytestrings on lines 33, 37 and 40 to Unicode literals, e.g.
lines.append(u':param %s %s' ...
.#
Thanks for that! I've fixed the snippet.
#
Thanks for the snippet! This works really sweet.
One addition to link to model classes to:
Secondly, it makes sense to keep the
setup()
inconf.py
only, and place the rest in adocs/_ext
folder. The Django docs do this, and it makes it really clean to implement.#
in django>=1.6
_meta._fields() has been removed please change it to _meta.fields as an attribute
#
If you try to use it with python 3 and django 1.7, you need to replace force_unicode() by force_text()
Thanks for the snippet
#
In >= django1.8 neither
_meta.fields
nor_meta.fields()
works, its now_meta.get_fields()
Also there is a typo on line 9 of the original solution,
from django.utils,encoding import force_unicode
should befrom django.utils.encoding import force_unicode
Thus the latest working solution, also incorporating the use of
force_text()
and links to model classes is:P.S. The django 1.9 bootstrapping I use at the top of conf.py is:
#
Also, you may need to add
before the line
verbose_name = force_text(field.verbose_name).capitalize()
#
Sorry, actually place the 'continue' skipping code above to be the first thing in the for loop, since ManyToOneRel and ManyToManyRel fields have no 'help_text'either.
#
Latest working solution for django 1.9 with all edits and corrections: https://gist.github.com/abulka/48b54ea4cbc7eb014308
#
Please login first before commenting.