A real-time debugging and monitoring dashboard for Django — monitor requests, queries, cache, Redis, exceptions, and more.
Project description
Django Scope
An elegant, real-time debug assistant for Django. Inspired by Laravel Telescope — built from the ground up for Django.
Django Scope gives you a beautiful dashboard to monitor everything happening in your application: requests, database queries, exceptions, model changes, cache operations, Redis commands, log entries, and much more. Unlike traditional debug tools that dump information into your terminal or a toolbar on the page, Django Scope provides a standalone SPA dashboard with real-time WebSocket updates — you see entries appear the instant they happen, no refresh needed.
Why Django Scope?
vs. Django Debug Toolbar
| Django Debug Toolbar | Django Scope | |
|---|---|---|
| Interface | Panel injected into HTML responses | Standalone dashboard (works with APIs, SPAs, mobile backends) |
| Real-time | No — only shows data for the current page load | Yes — WebSocket-powered live feed |
| API requests | Cannot inspect (no HTML to inject into) | Full request/response capture for all endpoints |
| Background tasks | Not supported | Commands, schedules, batches |
| Persistence | Gone on page refresh | Stored in database, browsable history |
| N+1 detection | Manual inspection of query list | Automatic detection with threshold alerts |
| Cache/Redis | Limited cache panel | Full operation-level cache + raw Redis command tracking |
| Exceptions | Not tracked | Full stack traces with source context |
| Production safe | Not recommended | Authorization gate, pruning, toggle recording |
vs. Silk
| Silk | Django Scope | |
|---|---|---|
| Scope | Requests + queries only | 17 watchers (requests, queries, cache, Redis, mail, models, logs, exceptions, events, commands, dumps, HTTP client, views, gates, notifications, schedules, batches) |
| Real-time | No — must refresh to see new data | WebSocket live feed |
| Frontend | Basic server-rendered HTML | Modern Vue.js SPA with dark/light themes and animations |
| Cache/Redis | Not tracked | Full auto-detection, no config needed |
| Model changes | Not tracked | Field-level change tracking on save/delete |
| N+1 detection | Not built-in | Automatic with configurable threshold |
vs. Sentry / New Relic / Datadog
Those are production monitoring and error tracking platforms (and great at what they do). Django Scope is a development and debugging tool — it's local, free, instant, and shows you everything at the code level without sending data to a third party. Use Django Scope during development, use Sentry in production. They complement each other.
Features
- 17 watchers covering every aspect of your Django application
- Real-time WebSocket updates — entries appear instantly in the dashboard
- N+1 query detection — automatically flags repeated query patterns
- Slow query highlighting — configurable threshold (default: 100ms)
- Beautiful Vue.js dashboard with dark and light themes
- Auto-detection — cache and Redis monitoring works automatically, no backend swapping required
- Request-scoped buffering — entries are grouped by request with a single bulk write for minimal performance impact
- Zero config for basics — add the app, add the middleware, done
- Authorization gate — control who can access the dashboard
- Pruning — automatic cleanup of old entries
Quick Start
1. Install
pip install django-scope
2. Add to INSTALLED_APPS
INSTALLED_APPS = [
"daphne", # Required for WebSocket support
# ... your apps
"telescope",
]
Note:
daphnemust be listed beforedjango.contrib.staticfiles(if present) so it can serve the ASGI application. If you don't need real-time WebSocket updates, you can skipdaphneand run under WSGI — the dashboard will still work, just without live updates.
3. Add the middleware
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"telescope.middleware.TelescopeMiddleware",
# ... other middleware
]
4. Add URL routing
from django.urls import include, path
urlpatterns = [
path("telescope/", include("telescope.urls")),
# ... your urls
]
5. Configure ASGI (for real-time WebSocket updates)
Create or update your asgi.py:
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from telescope.routing import websocket_urlpatterns
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": URLRouter(websocket_urlpatterns),
})
And in your settings:
ASGI_APPLICATION = "myproject.asgi.application"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer",
}
}
6. Run migrations
python manage.py migrate
7. Open the dashboard
Start your server and visit http://localhost:8000/telescope/.
Configuration
All configuration lives in a single TELESCOPE dictionary in your Django settings:
TELESCOPE = {
# Master switch — disable to completely turn off Django Scope
"ENABLED": True,
# Toggle recording without disabling (can be toggled from the dashboard)
"RECORDING": True,
# URL paths to ignore (regex patterns)
"IGNORE_PATHS": [r"^/telescope/", r"^/static/", r"^/favicon\.ico$"],
# HTTP methods to ignore
"IGNORE_METHODS": [], # e.g. ["OPTIONS", "HEAD"]
# Status codes to ignore
"IGNORE_STATUS_CODES": [], # e.g. [304]
# Queries slower than this are flagged as "slow" (milliseconds)
"SLOW_QUERY_THRESHOLD": 100,
# Flag N+1 when the same query pattern repeats this many times in one request
"N_PLUS_ONE_THRESHOLD": 5,
# Auto-prune entries older than this
"ENTRY_LIFETIME_HOURS": 24,
# Max size per entry payload (KB)
"ENTRY_SIZE_LIMIT": 64,
# Authorization callback — controls who can access the dashboard
# Receives the request, returns True/False. Defaults to settings.DEBUG.
"AUTHORIZATION": lambda request: request.user.is_superuser,
# Enable/disable individual watchers
"WATCHERS": {
"RequestWatcher": {"enabled": True},
"QueryWatcher": {"enabled": True},
"ExceptionWatcher": {"enabled": True},
"ModelWatcher": {"enabled": True},
"LogWatcher": {"enabled": True},
"CacheWatcher": {"enabled": True},
"RedisWatcher": {"enabled": False}, # Opt-in
"MailWatcher": {"enabled": True},
"ViewWatcher": {"enabled": True},
"EventWatcher": {"enabled": True},
"CommandWatcher": {"enabled": True},
"DumpWatcher": {"enabled": True},
"ClientRequestWatcher": {"enabled": False}, # Opt-in
"GateWatcher": {"enabled": True},
"NotificationWatcher": {"enabled": True},
"ScheduleWatcher": {"enabled": False}, # Requires Celery
"BatchWatcher": {"enabled": False}, # Requires Celery
},
}
The 17 Watchers
Request Watcher
Captures every HTTP request and response — method, path, headers, payload, response body, status code, duration, the resolved view function, and the user/session.
Query Watcher
Records every database query with SQL, bindings, execution time, and connection alias. Automatically detects:
- Slow queries — flagged when execution exceeds
SLOW_QUERY_THRESHOLD(default 100ms) - N+1 queries — flagged when the same query pattern repeats
N_PLUS_ONE_THRESHOLDtimes (default 5) in a single request
Works with any Django database backend (SQLite, PostgreSQL, MySQL, etc.) via Django's connection_created signal — every new database connection gets instrumented automatically.
Exception Watcher
Captures unhandled exceptions with the full stack trace, exception class, message, and the file/line where it occurred. Connects to Django's got_request_exception signal.
Model Watcher
Tracks model create, update, and delete operations via Django's pre_save, post_save, and post_delete signals. Records field-level changes on updates (old value vs. new value).
Log Watcher
Captures log entries from Python's logging module — all levels (DEBUG through CRITICAL). Installs a custom handler on the root logger so it catches logs from your code and third-party libraries alike.
Cache Watcher
Monitors all cache operations: get, set, delete, clear, get_many, set_many, delete_many, has_key, incr, decr. Records the key, value, hit/miss status, duration, and backend alias.
Auto-detection — works with any cache backend out of the box. No need to swap your CACHES backend setting. Works with django-redis, memcached, file cache, database cache, local memory cache, and any custom backend.
Redis Watcher
Captures raw Redis commands (SET, GET, LPUSH, EXPIRE, etc.) with arguments, duration, and connection info. Supports both:
redis-py— patchesStrictRedis.execute_commanddjango-redis— patchesDefaultClientfor Django cache operations that go through Redis
Enable it in settings:
"RedisWatcher": {"enabled": True},
Mail Watcher
Records outgoing emails — recipients, subject, body (HTML and plain text), and attachments. Uses a wrapping email backend.
View Watcher
Tracks template rendering — which templates are rendered, render duration, and the resolved view.
Event Watcher
Records Django signal dispatches. Automatically ignores Django's internal signals (pre_save, post_save, request_started, connection_created, etc.) to avoid flooding. Only records your custom signals and third-party signals.
Command Watcher
Captures management command execution — command name, arguments, exit code, output, and duration.
Dump Watcher
A telescope.dump() function you can call from anywhere in your code to inspect values:
import telescope
def my_view(request):
telescope.dump(some_complex_object, label="Debug: user data")
telescope.dump(request.headers, label="Request headers")
# ...
Each dump records the value, label, and the exact file/line where dump() was called.
Client Request Watcher
Monitors outgoing HTTP requests made by your application (via requests or httpx). Records URL, method, status code, headers, and duration.
Gate Watcher
Tracks permission checks — records which user, which permission, and whether it was granted or denied.
Notification Watcher
Records notifications sent to users — notification class, recipient, and delivery channels.
Schedule Watcher
Tracks Celery Beat scheduled task execution (requires Celery).
Batch Watcher
Monitors Celery group/chord batch job execution (requires Celery).
Management Commands
Prune old entries
# Prune entries older than the configured lifetime (default: 24 hours)
python manage.py telescope_prune
# Prune entries older than 6 hours
python manage.py telescope_prune --hours 6
Clear all entries
# Clear everything
python manage.py telescope_clear
# Clear only query entries
python manage.py telescope_clear --type query
# Clear only exceptions
python manage.py telescope_clear --type exception
You can also clear entries from the dashboard UI — each list page has a clear button.
Running Without WebSockets (WSGI)
If you can't run an ASGI server, Django Scope still works. The dashboard will function normally — you just won't get real-time live updates. The WebSocket indicator will show "Disconnected" and stop retrying after a few attempts. Data is still recorded and visible when you refresh or navigate.
Skip daphne from INSTALLED_APPS and the ASGI/channels configuration. Everything else stays the same.
Authorization
By default, the dashboard is only accessible when DEBUG = True. For more control, set an authorization callback:
TELESCOPE = {
"AUTHORIZATION": lambda request: request.user.is_staff,
}
Or a more complex check:
def scope_authorized(request):
if not request.user.is_authenticated:
return False
return request.user.email.endswith("@mycompany.com")
TELESCOPE = {
"AUTHORIZATION": scope_authorized,
}
Database
Django Scope creates 3 tables:
telescope_entries— all recorded entries (UUID, type, JSON content, batch ID, timestamps)telescope_entries_tags— searchable tags (e.g.slow,n+1,status:500,cache:hit)telescope_monitoring— selective monitoring configuration
All entry data is stored as JSON, keeping the schema simple and the queries fast.
Performance
Django Scope is designed to have minimal impact on your application:
- Request-scoped buffering — entries are collected in memory during a request and written in a single
bulk_createat the end, not one INSERT per event - Re-entrancy guard — Django Scope's own database operations are never recorded (no infinite loops)
- Path filtering — Dashboard routes and static files are excluded by default
- Async-safe — uses
contextvars(notthreading.local) so it works correctly with Django's async views - Configurable pruning — old entries are automatically cleaned up
Requirements
- Python 3.10+
- Django 4.2+
channels4.0+ (for WebSocket support)daphne(recommended, for ASGI server)
Optional:
redis/django-redis(for Redis watcher)celery(for Schedule and Batch watchers)
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_scope-1.0.1.tar.gz.
File metadata
- Download URL: django_scope-1.0.1.tar.gz
- Upload date:
- Size: 92.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abca3096b45e7711aa11d557b01702dd76cbfddb38168b2b7071bc8e08cbc775
|
|
| MD5 |
fc848ebd89074c003ac123933362246e
|
|
| BLAKE2b-256 |
c4a95344ade62af36a809ad42253f0e148bcb9d57323134333bbfad5b1521957
|
File details
Details for the file django_scope-1.0.1-py3-none-any.whl.
File metadata
- Download URL: django_scope-1.0.1-py3-none-any.whl
- Upload date:
- Size: 120.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95a9f0e9191dc530c29da280f2574291171eda0a0450658c0ccabbf822bc2da6
|
|
| MD5 |
8f5803d5a69993e16bfee0dd3dff3b2c
|
|
| BLAKE2b-256 |
cf4661940211a6561dcf5b8bf2edf711e322f73c8e7b95fa696d567272a91ced
|