Creating a plugin

A Plugin is a Python package, usually named with django-plugin- as a prefix.

Using cookiecutter

You can use the simonw/django-plugin to create an initial skeleton for your plugin, including automated tests, continuous integration and publishing to PyPI using GitHub Actions.

Install cookiecutter:

pipx install cookiecutter # or pip install

Then run the template like this:

cookiecutter gh:simonw/django-plugin

The template will ask you a number of questions. Here’s an example run:

  [1/6] plugin_name (): django-plugin-example
  [2/6] description (): A simple example plugin
  [3/6] hyphenated (django-plugin-example):
  [4/6] underscored (django_plugin_example):
  [5/6] github_username (): simonw
  [6/6] author_name (): Simon Willison

This creates a directory called django-plugin-example containing the skeleton of the plugin:

django-plugin-example
django-plugin-example/django_plugin_example
django-plugin-example/django_plugin_example/__init__.py
django-plugin-example/LICENSE
django-plugin-example/pyproject.toml
django-plugin-example/tests
django-plugin-example/tests/test_django_plugin_example.py
django-plugin-example/tests/test_project
django-plugin-example/tests/test_project/__init__.py
django-plugin-example/tests/test_project/settings.py
django-plugin-example/tests/test_project/urls.py
django-plugin-example/__init__.py
django-plugin-example/README.md
django-plugin-example/.gitignore
django-plugin-example/.github
django-plugin-example/.github/workflows
django-plugin-example/.github/workflows/publish.yml
django-plugin-example/.github/workflows/test.yml

Creating a plugin without the template

Your plugin should have a pyproject.toml file that defines it, looking something like this:

pyproject.toml

[project]
name = "django-plugin-special-header"
version = "0.1"
description = "Add a HTTP header to a Django app"
readme = "README.md"
authors = [{name = "Simon Willison"}]
license = {text = "Apache-2.0"}
classifiers = [
    "License :: OSI Approved :: Apache Software License"
]
dependencies = [
    "django",
    "djp",
]

[project.entry-points.djp]
django_plugin_special_header = "django_plugin_special_header"

The key part here is the [project.entry-points.djp] section. This tells the plugins system how to load the plugin - it should look for the django_plugin_special_header package or module.

Plugin directory structure

Next, create the directory structure. For this plugin that will look like this:

django-plugin-special-header/
    django_plugin_special_header/
        __init__.py
        middleware.py
    pyproject.toml
    README.md

The __init__.py file should contain the plugin hook implementations. For this middleware example that will look like this:

import djp


@djp.hookimpl
def middleware():
    return ["django_plugin_secial_header.middleware.SpecialHeaderMiddleware"]

The middleware.py file should contain the actual middleware implementation. Here’s an example:

class SpecialHeaderMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response["Special-Header"] = "This is a special HTTP header"
        return response

Trying out the plugin

In local development you can add this plugin to your existing Django environment by running this command:

pip install -e path/to/django-plugin-example