Django Watchman
django-watchman exposes a status endpoint for your backing services like databases, caches, and other services. It is currently at version 1.5.0 and maintains an active release cadence with regular updates and security fixes.
Common errors
-
TypeError: 'str' object is not iterable
cause The `WATCHMAN_CHECKS` setting in your Django `settings.py` is configured as a string instead of a sequence (list or tuple). This often happens when defining a single check without a trailing comma, e.g., `WATCHMAN_CHECKS = ('my.check')` instead of `WATCHMAN_CHECKS = ('my.check',)`.fixChange `WATCHMAN_CHECKS = 'my.check'` to `WATCHMAN_CHECKS = ('my.check',)` (for a tuple) or `WATCHMAN_CHECKS = ['my.check']` (for a list). -
Error connecting to Watchman: timed out waiting for response, while executing ('watch-project', 'my_app')cause This error typically occurs during Django development server startup when `pywatchman` (used by Django's `WatchmanReloader` for file watching) cannot connect to the Watchman daemon within the default timeout. This is not directly from `django-watchman` but is a common adjacent issue when using Watchman for auto-reloading.fixEnsure the Watchman daemon is installed and running (`brew install watchman` on macOS, or follow OS-specific instructions). If it still times out for large projects, you may need to increase the timeout for `pywatchman` or configure Watchman to ignore certain directories (e.g., `node_modules`). -
Watching for file changes with StatReloader
cause You have `pywatchman` and `django-watchman` installed, but Django's development server is still using the default `StatReloader` instead of `WatchmanReloader` for file change detection. This means Watchman is not being utilized for faster reloads.fixEnsure `pywatchman` is correctly installed in your environment (`pip install pywatchman`) and that your Django project is properly set up to find and use it. In most cases, just having `pywatchman` installed is enough, but sometimes environment issues or conflicting settings can prevent its detection. Restarting your development server is often necessary. -
Database check failed: Access denied for user 'X'@'localhost' (using password: YES)
cause The database check executed by `django-watchman` failed due to incorrect database credentials or permissions configured in your Django `DATABASES` settings.fixVerify that the database user, password, host, and port configured in your Django `settings.py` for the database connection are correct and have the necessary privileges to connect and perform a basic `SELECT` query.
Warnings
- breaking Version 1.0.0 dropped support for Python 2 and Django versions older than 2.0. Additionally, it removed the dependency on `django-jsonview` in favor of Django's built-in `JsonResponse`.
- deprecated Prior to version 1.3.0, `django-watchman` used `django.conf.urls.url()`. This function has been deprecated in modern Django versions (3.1+), which now primarily use `re_path()` or `path()`.
- gotcha When configuring `WATCHMAN_CHECKS` in your settings, ensure it is a sequence (e.g., a list or a tuple), not a single string. For a tuple with one item, remember the trailing comma: `('my.custom.check',)`.
- gotcha The database health check in `django-watchman` might fail for Oracle databases when using `SELECT 1` without a `FROM` clause.
- gotcha Version 1.4.0 included a security fix for a Regular Expression Denial of Service (ReDoS) vulnerability in the Authorization header parsing. Crafted input could lead to polynomial backtracking.
Install
-
pip install django-watchman
Imports
- watchman.urls
from django.conf.urls import url, include # url() is deprecated in modern Django
from django.urls import re_path, include urlpatterns = [ re_path(r'^watchman/', include('watchman.urls')), ] - watchman.views.bare_status
from django.urls import path from watchman.views import bare_status urlpatterns = [ path('watchman/bare/', bare_status), ]
Quickstart
import os
# settings.py
INSTALLED_APPS = [
# ... other apps
'watchman',
]
# urls.py
from django.urls import re_path, include
urlpatterns = [
# ... other url patterns
re_path(r'^watchman/', include('watchman.urls')),
# For a minimal status endpoint (optional)
# from watchman.views import bare_status
# re_path(r'^watchman/bare/$', bare_status),
]
# Optional: Protect with a token (add to settings.py)
# WATCHMAN_TOKEN = os.environ.get('WATCHMAN_TOKEN', 'your_secret_token')
# Run checks from command line (optional)
# python manage.py watchman -v 2