django-sphinx-hosting

Current version is 1.3.1.

This reusable Django application provides models, views, permissions, REST API endpoints and management commands for making a private Sphinx documentation hosting platform.

This is useful for when you want Sphinx documentation for your internal software projects, but you do not want that documentation do be shared with a third-party.

Installation

To install from PyPI:

pip install django-sphinx-hosting

If you want, you can run the tests:

python -m unittest discover

Features

  • Users must be authenticated to view docs

  • Multiple levels of privileges within the system based on Django authentication

  • Manage multiple versions of your docs per project

  • Automatically build and display navigation for each version of your documentaion

  • Renders all documentation published within with a consistent theme

  • Tag projects with classifiers to refine searching and filtering

  • Search across all projects

  • Use REST API to programmatically interact with the system. Useful for integrating into a CI/CD system

Configuration

Update INSTALLED_APPS

As with most Django applications, you should add django-sphinx-hosting and its key dependencies to the INSTALLED_APPS within your settings file (usually settings.py).

Example:

INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.messages',
   'django.contrib.sessions',
   'django.contrib.sites',

   # ---------- add these ----------------
   'rest_framework',
   'rest_framework.authtoken',
   'django_filters',
   'drf_spectacular',
   'crispy_forms',
   'crispy_bootstrap5',
   'haystack',
   'academy_theme',
   'wildewidgets',
   'sphinx_hosting',
   'sphinx_hosting.api'
   # -------- done add these -------------

   # Then your usual apps...
   'blog',
]

Configure django-sphinx-hosting itself

For django-sphinx-hosting itself, you’ll typically want to add a SPHINX_HOSTING_SETTINGS dict to localize django-sphinx-hosting to your organization.

Full example:

SPHINX_HOSTING_SETTINGS = {
   'LOGO_IMAGE': 'core/images/my-org-logo.png',
   'LOGO_WIDTH': '75%',
   'LOGO_URL': 'https://www.example.com',
   'SITE_NAME': 'MyOrg Documentation'
}
LOGO_IMAGE

A Django filesystem path to the image you want to use for the logo at the top of the navigation sidebar.

LOGO_WIDTH

Any valid CSS width specifier. This will be applied to the LOGO_IMAGE.

LOGO_URL

When a user clicks the LOGO_IMAGE, they’ll be sent to this URL.

SITE_NAME

This will be used in the HTML title tags for each page, and wil be used as the alt tag for the LOGO_IMAGE.

Configure django-wildewidgets

All HTML in django-sphinx-hosting is generated by django-wildewidgets widgets. We use the django-theme-academy to provide the HTML boilerplate to house the widget output, and django-crispy-forms for our form rendering.

Add this code to your settings.py to configure them properly:

# crispy-forms
# ------------------------------------------------------------------------------
CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap5'
CRISPY_TEMPLATE_PACK = 'bootstrap5'

# django-theme-academy
# ------------------------------------------------------------------------------
ACADEMY_THEME_SETTINGS = {
   # Header
   'APPLE_TOUCH_ICON': 'core/images/apple-touch-icon.png',
   'FAVICON_32': 'core/images/favicon-32x32.png',
   'FAVICON_16': 'core/images/favicon-16x16.png',
   'FAVICON': 'core/images/favicon.ico',
   'SITE_WEBMANIFEST': 'core/images/site.webmanifest',

   # Footer
   'ORGANIZATION_LINK': 'https://github.com/caltechads/django-sphinx-hosting',
   'ORGANIZATION_NAME': 'Sphinx Hosting',
   'ORGANIZATION_ADDRESS': '123 Main Street, Everytown, ST',
   'COPYRIGHT_ORGANIZATION': 'Sphinx Hosting',
   'FOOTER_LINKS': [
      ('https://example.com', 'Organization Home'),
      ('https://example.com/documents/privacy.pdf', "Privacy Policy")
   ]
}

# django-wildewidgets
# ------------------------------------------------------------------------------
WILDEWIDGETS_DATETIME_FORMAT = "%Y-%m-%d %H:%M %Z"

For ACADEMY_THEME_SETTINGS, localize to your organization by updating all the settings appropriately.

FAVICON_*, APPLE_TOUCH_ICON and SITE_WEBMANIFEST

Set these to the Django filesystem path to the files you want to use.

FOOTER_LINKS

Add links to the footer by listing 2-tuples of ("__URL__", "__LABEL__")

Configure Haystack

We use django-haystack to support our documentation search feature, but it is up to you what specific backend you want to configure. See Haystack: Configuration for instructions on how to configure Haystack for different backends.

Here is example settings.py code for using Elasticsearch 7.x as our search backend:

HAYSTACK_CONNECTIONS = {
   'default': {
      'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
      'URL': 'http://sphinx-hosting-search.example.com:9200/',
      'INDEX_NAME': 'sphinx_hosting',
   },
}

If you want your search index to be updated automatically when versions of your documentation are uploaded, add this to settings.py:

# This will cause the search index to be updated whenever a SphinxPage is
# saved or deleted.
HAYSTACK_SIGNAL_PROCESSOR = 'sphinx_hosting.signals.SphinxHostingSignalProcessor'

Configure Django REST Framework

To make the django-sphinx-hosting API work, add this code to your settings.py:

# djangorestframework
# ------------------------------------------------------------------------------
REST_FRAMEWORK = {
   # https://www.django-rest-framework.org/api-guide/parsers/#setting-the-parsers
   'DEFAULT_PARSER_CLASSES': ('rest_framework.parsers.JSONParser',),
   # https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
   'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.TokenAuthentication',),
   # https://django-filter.readthedocs.io/en/master/guide/rest_framework.html
   'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
   # https://www.django-rest-framework.org/api-guide/pagination/#limitoffsetpagination
   'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
   # https://github.com/tfranzel/drf-spectacular
   'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
   'PAGE_SIZE': 100,
}

# drf-spectacular
# ------------------------------------------------------------------------------
# https://drf-spectacular.readthedocs.io/en/latest/settings.html
SPECTACULAR_SETTINGS = {
   'SCHEMA_PATH_PREFIX': r'/api/v1',
   'SERVERS': [
      {
            'url': 'https://localhost',
            'description': 'Django Sphinx Hosting'
      }
   ],
   'TITLE': 'YOUR_SITE_NAME'
   'VERSION': __version__,
   'DESCRIPTION': """__YOUR_DESCRIPTION__HERE"""
}

For DEFAULT_AUTHENTICATION_CLASSES, use whatever authentication class you want – we’re just using TokenAuthentication here as an example. For the rest of the settings, you’ll need at least what we’ve detailed above, but feel free to add to them if you have additional API views you need to support in your own application code.

Update your top-level urlconf

from django.urls import path, include

from sphinx_hosting import urls as sphinx_hosting_urls
from sphinx_hosting.api import urls as sphinx_hosting_api_urls
from wildewidgets import WildewidgetDispatch

urlpatterns = [
   path('/docs/', include(sphinx_hosting_urls, namespace='sphinx_hosting')),
   path('/docs/wildewidgets_json', WildewidgetDispatch.as_view(), name='wildewidgets_json'),
   path('api/v1/', include(sphinx_hosting_api_urls, namespace='sphinx_hosting_api')),
]