Django Simple CAPTCHA
django-simple-captcha is a robust yet easy-to-use Django application for integrating CAPTCHA into forms. It supports various CAPTCHA types including image and audio. Currently at version 0.6.3, it is actively maintained with regular updates to support new Django versions and address user feedback.
Common errors
-
django.urls.exceptions.NoReverseMatch: 'captcha' is not a registered namespace
cause The CAPTCHA URL patterns are not included in your project's `urls.py`.fixAdd `path('captcha/', include('captcha.urls'))` to your project's `urls.py` file. -
ModuleNotFoundError: No module named 'captcha.fields'
cause The `django-simple-captcha` library is either not installed or 'captcha' is missing from `INSTALLED_APPS`.fixEnsure `pip install django-simple-captcha` has been run and 'captcha' is in your `settings.INSTALLED_APPS`. -
Captcha image not showing/broken link
cause This is often due to incorrect static files configuration or `DEBUG=False` in development without proper static file serving.fixCheck your `settings.STATIC_URL`, `STATIC_ROOT`. In production, ensure `python manage.py collectstatic` has been run and your web server is configured to serve static files from `STATIC_ROOT` via `STATIC_URL`. -
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
cause Django requires a `SECRET_KEY` in `settings.py` for security functions, including session management and CSRF tokens, which CAPTCHA forms implicitly use.fixSet a secure `SECRET_KEY` in your `settings.py`. For example: `SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'default-in-dev-only')`.
Warnings
- gotcha Ensure 'captcha' is added to your `INSTALLED_APPS` and `path('captcha/', include('captcha.urls'))` is configured in your project's `urls.py`. Without these, CAPTCHA images or forms will not render correctly, leading to `NoReverseMatch` errors or missing images.
- gotcha By default, the CAPTCHA image relies on Django's static files system. If your static files are not correctly configured (especially in production), the CAPTCHA image might not appear. Ensure `STATIC_URL` and `STATIC_ROOT` are properly set and static files are collected.
- deprecated Older versions of django-simple-captcha (pre-0.6.1) could leave temporary audio files, potentially filling up disk space. While fixed in 0.6.1, users on older versions should consider upgrading or implementing custom cleanup.
- gotcha Version 0.6.2 made `djangorestframework` an optional dependency. If you were relying on DRF integration and upgrading from a version before 0.6.2, ensure `djangorestframework` is explicitly installed if you need it, as it might no longer be pulled in automatically.
Install
-
pip install django-simple-captcha
Imports
- CaptchaField
from captcha.fields import CaptchaField
- CaptchaWidget
from captcha.widgets import CaptchaWidget
Quickstart
import os
import django
from django.conf import settings
# Minimal Django setup for demonstration
if not settings.configured:
settings.configure(
INSTALLED_APPS=['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'captcha'],
MIDDLEWARE=[
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
],
ROOT_URLCONF='__main__',
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
],
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'a-very-secret-key-for-testing-only'),
STATIC_URL='/static/',
DEBUG=True
)
django.setup()
from django import forms
from django.http import HttpResponse
from django.urls import path, include
from django.views.generic import FormView
from captcha.fields import CaptchaField
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
captcha = CaptchaField()
class ContactView(FormView):
template_name = 'form_template.html' # In a real app, this would be a file
form_class = ContactForm
success_url = '/success/'
def form_valid(self, form):
# Process the form data (e.g., send email)
print("Form is valid! Subject:", form.cleaned_data['subject'])
return super().form_valid(form)
def get(self, request, *args, **kwargs):
# For quickstart, just render the form without a real template
form = self.get_form()
html = f"""
<form method="post">
<p>{{ form.subject.label_tag }} {{ form.subject }}</p>
<p>{{ form.message.label_tag }} {{ form.message }}</p>
<p>{{ form.captcha.label_tag }} {{ form.captcha }}</p>
<button type="submit">Submit</button>
{% csrf_token %}
</form>
"""
return HttpResponse(html.replace('{% csrf_token %}', request.META.get('CSRF_COOKIE', '')))
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return HttpResponse("Form invalid! " + str(form.errors))
urlpatterns = [
path('', ContactView.as_view(), name='contact'),
path('captcha/', include('captcha.urls')),
path('success/', lambda request: HttpResponse('Form submitted successfully! CAPTCHA was valid.')),
]
# To run this minimal example (requires a test runner or manual URL dispatch)
# from django.urls import resolve
# from django.test import RequestFactory
#
# factory = RequestFactory()
#
# # Test GET request
# request = factory.get('/')
# response = resolve('/').func(request)
# print("\nGET Response:", response.status_code, response.content.decode()[:200], "...")
#
# # Test POST request (replace with actual CAPTCHA values from GET request if needed)
# # This part is tricky to automate without actually solving the captcha.
# # You would typically submit a solved captcha value.
# # Example POST data, assuming 'captcha_0' is the key for the hash, 'captcha_1' for the response:
# # post_data = {'subject': 'Test Subject', 'message': 'Test Message', 'captcha_0': 'hash_value', 'captcha_1': 'solved_text'}
# # request = factory.post('/', post_data)
# # response = resolve('/').func(request)
# # print("\nPOST Response:", response.status_code, response.content.decode()[:200], "...")
print("Setup complete. You would normally run this via `manage.py runserver`.")
print("To access the form, configure your Django project's urls.py with `path('captcha/', include('captcha.urls'))` and `path('', views.ContactView.as_view())`")