Skip to content

Django

Last updated View as MarkdownAgent setup

Django is supported in Python Workers.

Django applications use protocols called the Web Server Gateway Interface (WSGI) or Asynchronous Server Gateway Interface (ASGI).

This means that Django never reads from or writes to a socket itself. A WSGI/ASGI application expects to be hooked up to a WSGI/ASGI server, such as uvicorn. The WSGI/ASGI server handles all of the raw sockets on the application’s behalf.

Python Workers provide adaptors for both WSGI and ASGI, so you can choose any based on whether your Django application deploys to WSGI or ASGI.

Quick start

To get started with Django in Python Workers, follow these steps:

  1. Create a Django project using pywrangler init:

    uv run pywrangler init django-worker --template https://github.com/cloudflare/python-workers-examples/tree/main/django
    cd django-worker
  2. Run your worker locally:

    uv run pywrangler dev

Choose between ASGI and WSGI

Your Django application needs to be served using either ASGI or WSGI. While Python workers is optimized for ASGI, you can still use WSGI which is compatible with Django.

Serve a WSGI application

Build the application object with get_wsgi_application() and pass it to workers.wsgi.fetch:

src/index.pypython
import os

from django.core.wsgi import get_wsgi_application
from workers import wsgi

# your Django settings module
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

app = get_wsgi_application()

Default = wsgi.entrypoint(app)

wsgi.fetch takes the application object, the incoming request, and the environment. It exposes your bindings to the application through scope["env"].

Serve an ASGI application

Build the application object with get_asgi_application() and pass it to workers.asgi.fetch:

src/index.pypython
import os

from django.core.asgi import get_asgi_application
from workers import asgi

# your Django settings module
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

app = get_asgi_application()

Default = asgi.entrypoint(app)

asgi.fetch takes the application object, the incoming request, and the environment. It exposes your bindings to the application through scope["env"].

Configure Django settings

Pass secrets

If you need a secret (like SECRET_KEY) in your Django settings, you can read it from a Worker secret:

src/app/settings.pypython
from workers import env

SECRET_KEY = env.DJANGO_SECRET_KEY

Create the secret with uv run pywrangler secret put DJANGO_SECRET_KEY.

Use Cloudflare storage as Django backends

You can use Cloudflare D1 and Durable Objects as Django database backends. To use them, you need to install the django-cf package.

Add django-cf to your dependencies:

[project]
dependencies = [
    "django",
    "django-cf",
]

Database backends

django-cf provides two SQLite-compatible backends using Cloudflare's D1 and Durable Objects. Both drive the synchronous Django ORM, so serve your application through the WSGI path when you use them.

D1 backend

To use D1 as a database backend, first setup your D1 database in Wrangler:

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "my-database",
      "database_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
  ]
}
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Then, configure the backend in your Django settings:

src/app/settings.pypython
DATABASES = {
    "default": {
        "ENGINE": "django_cf.db.backends.d1",
        # should match the binding name in your wrangler.jsonc
        "CLOUDFLARE_BINDING": "DB",
    }
}

You are all set. Your Django application now uses D1 as its database backend.

src/index.pypython
import os

from django.core.wsgi import get_wsgi_application
from workers import WorkerEntrypoint, wsgi

# your Django settings module
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

application = get_wsgi_application()


class Default(WorkerEntrypoint):
    async def fetch(self, request):
        return await wsgi.fetch(application, request, self.env)

Durable Objects backend

To use Durable Objects as a database backend, first setup your Durable Objects binding in Wrangler:

{
  "durable_objects": {
    "bindings": [
      {
        "name": "DO_STORAGE",
        "class_name": "DjangoDurableObject"
      }
    ]
  },
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["DjangoDurableObject"]
    }
  ]
}
[[durable_objects.bindings]]
name = "DO_STORAGE"
class_name = "DjangoDurableObject"

[[migrations]]
tag = "v1"
new_sqlite_classes = [ "DjangoDurableObject" ]

Then, configure the backend in your Django settings:

src/app/settings.pypython
DATABASES = {
    "default": {
        "ENGINE": "django_cf.db.backends.do",
    }
}

Then, update your Python worker as follows:

src/index.pypython
import os

from django.core.wsgi import get_wsgi_application
from django_cf.db.backends.do.storage import set_storage
from workers import WorkerEntrypoint, DurableObject, wsgi

# your Django settings module
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

application = get_wsgi_application()


class DjangoDurableObject(DurableObject):
    def __init__(self, ctx, env):
        super().__init__(ctx, env)

        # Tell Django to use the Durable Object storage
        set_storage(self.ctx.storage.sql)

    async def fetch(self, request):
        return await wsgi.fetch(application, request, self.env)


class Default(WorkerEntrypoint):
    async def fetch(self, request):
        id = self.env.DO_STORAGE.idFromName("my-do-backend")
        stub = self.env.DO_STORAGE.get(id)
        return await stub.fetch(request)

More examples

Clone the cloudflare/python-workers-examples repository and run Django examples:

Was this helpful?