Mike Slinn
Mike Slinn

Documenting Custom Django & Django-Oscar Apps

Published 2021-05-26. Last modified 2021-05-28.
Time to read: about 3 minutes.

This article is categorized under Django, Django-Oscar.

Documenting custom Django apps is made convenient by using the Django admin documentation generator. Django documentation standards are defined here. These documentation standards were written for Django contributors; Django uses Sphinx for creating documentation. The Django admin documentation generator supports a subset of Sphinx-compatible reStructured text.

Installation

The Python docutils library must be installed in the virtual Python installation before the documentation feature can be configured. For me, that meant adding a line consisting of just had one word, docutils, to dev.requirements.in, and typing:

Shell
(aw) $ pip install docutils
Collecting docutils
  Downloading docutils-0.17.1-py2.py3-none-any.whl (575 kB)
     |████████████████████████████████| 575 kB 1.7 MB/s
Installing collected packages: docutils
Successfully installed docutils-0.17.1 

Tragedy of the Commons

Unlike most of Python, Docutils is still on SourceForge and uses Subversion instead of git. Clearly this module is stable, but it has been allowed to grow moldy for 10 years or more. The plea for help is clearly visible, and it is at revision 8631!

There's a To Do list full of ideas awaiting a champion.

Beyond just needing a champion, what is really needed is proper funding, which means corporations that use Django should realize that their free ride on F/OSS is not sustainable.

Setup

I added the following to INSTALLED_APPS and MIDDLEWARE in settings:

settings
INSTALLED_APPS = [
  ... 
  'django.contrib.admindocs',
  ...
]

MIDDLEWARE = [
  ... 
  'django.contrib.admindocs.middleware.XViewMiddleware',
  ...
] 

A new route is required, just one new route for the entire Django webapp. For my Django webapp, the new route was placed in main/urls.py, just above the admin route. The documentation was not sufficiently explicit about this for me to understand exactly what was required, so at first, I added the route to all of my Django apps. This caused one of my apps to hijack the URL. The correct placement of the URL is:

main/urls.py
from django.urls import include, path, re_path

urlpatterns = [
  ... 
  path(route='admin/doc/', include('django.contrib.admindocs.urls')),
  re_path(route=r'^admin\/?', view=admin.site.urls),
  ... 

Autogeneration

Each time the Django webapp is restarted the documentation is regenerated. The process is very quick. I found it convenient to view the generated documentation for a model class, and tweak it, restarting the webapp each time that I made a significant change so I could inspect the result.

Upon reviewing the generated documentation, I realized that I had not been providing help_text attributes for many of my Django model field definitions. The Django documentation generator incorporated the help_text attributes into the generated documentation. help_text attributes are not HTML-escaped, so they must not contain HTML.

I was unable to find documentation on formatting or linking to model fields.

Viewing the Documentation

The entire Django webapp’s documentation is generated when the Django webapp starts. After setting up, a new link called Documentation was displayed on the admin page, and it pointed to http://localhost:8000/admin/doc/.

Each of the links on the main documentation page is shown in the images below.

Tag Documentation

Tags are viewable at http://localhost:8000/admin/doc/tags/.

Filter Documentation

Filters are viewable at http://localhost:8000/admin/doc/filters/.

Model Documentation

A clickable listing of all Django models for your webapp is available at http://localhost:8000/admin/doc/models/ Some generally useful Django-Oscar models to view documentation for are:

View Documentation

Views are viewable at http://localhost:8000/admin/doc/views/. The views are summarized on one page, with the first docstring sentence displayed. Clicking on a view displays the entire docstring.

Bookmarklets

About Bookmarklets

Bookmarklets are broken

The official documentation for Django bookmarklets is skimpy and inaccurate, and all the other documentation on this feature that I was able to find is badly out of date and incomplete. The feature is completely broken, another example of Django bitrot.

This (updated) information is based on two sources, plus my own investigation:

Bookmarklets are bits of JavaScript to be dragged into your browser’s bookmarks bar, and then clicked when visiting pages on your Django-powered website.

Bookmarkets will be activated for any authenticated user who has the is_staff flag set True, or if the website is served from an IP address specified in the INTERNAL_IPS setting. I split my Django webapp’s settings into dev, prod and test; the INTERNAL_IPS settings for dev are:

settings/dev.py
INTERNAL_IPS = [
    '127.0.0.1',
]

Using Bookmarklets

To make a bookmarklet available, drag a bookmarklet link from the admin page (usually http://localhost:8000/admin/doc/bookmarklets/) to your web browser’s bookmarks toolbar, or right-click the link and add it to your bookmarks. I used Firefox to create a bookmark folder called Django, and added a link for every type of bookmarklet. The resulting bookmark folder looked like this:

Now I am supposed to be able to select bookmarklets from the non-admin pages in my webapp. Here are my results of using each type of bookmarklet on the autogenerated documentation for my core.Formulation Django model class, which was displayed at http://localhost:8000/admin/doc/models/core.formulation/:

Documentation for this page
This error message appeared: formulation with ID “doc/views/django.contrib.admin.options.ModelAdmin.changelist_view” doesn’t exist. Perhaps it was deleted?
Show object ID
Some of my webapp pages did not respond to this bookmarklet, while others displayed a small div which did not contain useful information.
Edit this object (current window)
Nothing happened. No error message on the JavaScript console.
Edit this object (new window)
Nothing happened. No error message on the JavaScript console.