Skip to main content

RSGI adapter for Django applications

Project description

django-rsgi

Deploy Django with media serving in a single process — no nginx, no gunicorn.

django-rsgi lets you serve your Django app and user-uploaded media files from a single Granian process. No reverse proxy for static/media files, no separate WSGI server — just one process that handles everything.

It does this by adapting Django to speak RSGI (Rust Server Gateway Interface), Granian's native protocol. Your Django code stays unchanged — django-rsgi handles the translation.

Features

  • Single-process deployment — Granian serves HTTP, Django handles logic, and media files are served efficiently with zero-copy and range requests
  • FileResponse optimization — Django's FileResponse objects are automatically served using Granian's response_file() for zero-copy file delivery
  • HTTP Range requests — Partial content delivery for video streaming and resumable downloads, out of the box
  • Authenticated file serving — Serve user uploads behind login_required or custom permissions with path traversal protection
  • Async-native — Full support for Django's async views and streaming responses
  • Django 6.0+ — Built for modern Django with Python 3.12+

Installation

pip install django-rsgi[server]

Or using uv:

uv pip install django-rsgi[server]

The [server] extra installs Granian. If you only need the RSGI handler (e.g., for testing or use with another RSGI server), you can install without it:

pip install django-rsgi

Quick Start

1. Add to INSTALLED_APPS

INSTALLED_APPS = [
    ...
    'django_rsgi',
]

2. Generate your RSGI entry point

python manage.py rsgi_install myproject

This creates myproject/rsgi.py configured for your project — similar to the wsgi.py and asgi.py that Django generates.

3. Run with Granian

python manage.py serve

Or run Granian directly:

granian --interface rsgi myproject.rsgi:application

Try the demo

The example_project/ directory is a working Django app with video streaming, SSE, and media serving:

cd example_project
./bin/setup    # migrations, fixtures, admin user
uv run ./manage.py serve
# Visit http://localhost:8000

Advanced Usage

Async Views and Streaming Responses

django-rsgi supports Django's async views for efficient streaming responses and Server-Sent Events. See the Django async documentation for detailed information on async views.

The included example project demonstrates a simple SSE endpoint at /sse-time/ that streams the current time every second.

Static File Serving

django-rsgi automatically optimizes Django's FileResponse objects for efficient file serving. This includes:

  • Zero-copy file serving: Files are served directly from disk using Granian's response_file() method
  • HTTP Range requests: Automatic support for partial content delivery (useful for video streaming and resumable downloads)
  • Efficient streaming: Large files are streamed in chunks without loading into memory

Development Mode

In development (DEBUG=True), use Django's built-in static file serving:

# urls.py
from django.contrib.staticfiles.urls import staticfiles_urlpatterns

urlpatterns = [
    # your patterns...
]

if settings.DEBUG:
    urlpatterns += staticfiles_urlpatterns()

Production Mode

In production, configure Granian to serve static files directly:

python manage.py collectstatic  # Collect static files first
granian --interface rsgi myproject.rsgi:application \
    --static-path-route /static \
    --static-path-mount /path/to/staticfiles

Or use the management command which handles this automatically:

python manage.py serve  # Automatically configures static file serving based on DEBUG setting

Reload Settings

In development mode, manage.py serve enables auto-reload. You can exclude directories and paths from the file watcher via Django settings:

# settings.py
GRANIAN_RELOAD_IGNORE_DIRS = ["node_modules", ".git"]
GRANIAN_RELOAD_IGNORE_PATHS = ["data/cache.db"]

Authenticated File Serving

For files that require authentication or permission checks (like user uploads), django-rsgi provides secure file serving:

from django_rsgi.urls import media_urlpatterns

urlpatterns = [
    # your patterns...
]

if settings.DEBUG:
    # Serve MEDIA_ROOT with login_required by default
    urlpatterns += media_urlpatterns()

For custom permissions:

from django.contrib.auth.decorators import permission_required
from django_rsgi.serve import serve_file
from django_rsgi.urls import media_urlpatterns

# Use a custom permission check
urlpatterns += media_urlpatterns(
    view=permission_required('can_view_files')(serve_file)
)

# Or serve from a different root
urlpatterns += media_urlpatterns(
    prefix='/private/',
    document_root='/path/to/private/files'
)

Security Features:

  • Path traversal protection using Python's pathlib
  • No directory listing
  • Automatic MIME type detection
  • ETag support for efficient caching
  • If-Modified-Since and If-None-Match handling
  • All FileResponse optimizations (range requests, zero-copy serving)

Note: If your files don't need authentication, use Django's built-in static file serving with django.conf.urls.static.static() which is also optimized by django-rsgi.

FAQ

What about WebSockets?

Django itself has no built-in WebSocket support — even with ASGI, you need Django Channels for that. django-rsgi follows the same approach: it handles HTTP only. Use Django Channels or a dedicated WebSocket server alongside Granian if you need WebSockets.

Development

Setting up the development environment

This project uses uv as the package manager for faster and more reliable dependency management.

# Clone the repository
git clone https://github.com/myers/django-rsgi
cd django-rsgi

# Create a virtual environment and install dev dependencies
uv sync

# Install commit hooks
prek install

Running tests

bin/test

Arguments are passed through to pytest:

bin/test -xvs                              # verbose with stop on first failure
bin/test tests/test_rsgi_handler.py        # specific file
bin/test --cov=django_rsgi                 # with coverage

License

MIT License

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_rsgi-1.0.0.tar.gz (10.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_rsgi-1.0.0-py3-none-any.whl (25.8 kB view details)

Uploaded Python 3

File details

Details for the file django_rsgi-1.0.0.tar.gz.

File metadata

  • Download URL: django_rsgi-1.0.0.tar.gz
  • Upload date:
  • Size: 10.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_rsgi-1.0.0.tar.gz
Algorithm Hash digest
SHA256 bf644403c6dd5376e0b1d1785cf9e39a99a09c3b2fe9997c26897b11418768df
MD5 35c814ae56d00fd350a9406f54c3cf9c
BLAKE2b-256 052e19fd237f2daee03340b472b234ff5dfbcfbe466df5929538559c47f6392a

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_rsgi-1.0.0.tar.gz:

Publisher: publish.yml on myers/django-rsgi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_rsgi-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: django_rsgi-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 25.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_rsgi-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c6f0f2a69c521a46f478b17cadca49440469aea9832a06cf95aff5d1e6f536b6
MD5 5cbc86542853fe19feb24e4b83cccd08
BLAKE2b-256 e40161abd33def055d624ea216739a5d645c586a1a12d9ca9c64a9d21b78973a

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_rsgi-1.0.0-py3-none-any.whl:

Publisher: publish.yml on myers/django-rsgi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page