debug:django
npx skills add https://github.com/snakeo/claude-debug-and-refactor-skills-plugin --skill debug:django
Agent 安装分布
Skill 文档
Django Debugging Guide
Overview
Django debugging requires understanding the framework’s layered architecture: settings, URL routing, views, templates, models, and middleware. Effective debugging follows a systematic approach – reproducing the bug, isolating the problem, gathering evidence, and implementing verified fixes.
Key principles:
- Reproduce first: Repeat the exact steps that cause the issue
- Isolate systematically: Identify the exact module, function, or code path
- Gather evidence: Collect error messages, stack traces, logs, and database state
- Test your fix: Verify the solution with automated tests
Common Error Patterns
TemplateDoesNotExist
Cause: Django cannot find the specified template file.
Investigation steps:
- Check template exists in the correct directory
- Verify
TEMPLATES['DIRS']setting includes your template directories - Check for typos in template path
- Ensure app is in
INSTALLED_APPSif using app-specific templates
# Check template configuration
python manage.py shell -c "from django.conf import settings; print(settings.TEMPLATES)"
# Verify template directories exist
python manage.py shell -c "import os; from django.conf import settings; print([d for d in settings.TEMPLATES[0]['DIRS'] if os.path.exists(d)])"
ImproperlyConfigured
Cause: Django configuration error in settings.py or environment.
Common causes:
- Missing or incorrect
DJANGO_SETTINGS_MODULE - Invalid database configuration
- Missing required settings
- Incorrect app configuration
# Check settings module
echo $DJANGO_SETTINGS_MODULE
# Validate configuration
python manage.py check
# Compare with defaults
python manage.py diffsettings
IntegrityError / Database Errors
Cause: Database constraint violations or missing migrations.
OperationalError (missing column/table):
# Check migration status
python manage.py showmigrations
# Create missing migrations
python manage.py makemigrations
# Apply migrations
python manage.py migrate
# Check SQL that would be executed
python manage.py sqlmigrate <app_name> <migration_number>
IntegrityError (constraint violation):
# Check for duplicates before insert
from django.db import IntegrityError
try:
obj.save()
except IntegrityError as e:
# Log the error, check constraint name
print(f"Constraint violation: {e}")
N+1 Query Problems
Cause: Inefficient database queries in loops.
Detection:
# In settings.py (development only)
LOGGING = {
'version': 1,
'handlers': {'console': {'class': 'logging.StreamHandler'}},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
}
}
}
Solution – use select_related/prefetch_related:
# Bad: N+1 queries
for order in Order.objects.all():
print(order.customer.name) # Extra query per order
# Good: Single query with join
for order in Order.objects.select_related('customer'):
print(order.customer.name)
# For many-to-many or reverse foreign keys
orders = Order.objects.prefetch_related('items')
Migration Conflicts
Cause: Multiple developers creating migrations on same app.
# View migration graph
python manage.py showmigrations --plan
# Merge conflicting migrations
python manage.py makemigrations --merge
# Reset migrations (development only - DANGEROUS)
python manage.py migrate <app_name> zero
python manage.py makemigrations <app_name>
python manage.py migrate <app_name>
CSRF Verification Failures
Cause: Missing CSRF token or misconfigured trusted origins.
Checklist:
- Include
{% csrf_token %}in forms - Check
CSRF_TRUSTED_ORIGINSfor HTTPS sites - Verify middleware includes
CsrfViewMiddleware - For AJAX, include CSRF token in headers
# settings.py - for cross-origin requests
CSRF_TRUSTED_ORIGINS = [
'https://your-domain.com',
]
Import Errors / Circular Imports
Cause: Circular dependencies between modules.
Detection:
# Check for import errors
python -c "import your_app"
# Verbose import tracing
python -v -c "import your_app" 2>&1 | grep "import"
Solutions:
- Move imports inside functions (lazy import)
- Restructure modules to break cycles
- Use string references for model relationships
# Avoid circular import with lazy import
def my_function():
from other_module import SomeClass # Import inside function
return SomeClass()
# Use string reference in ForeignKey
class Order(models.Model):
customer = models.ForeignKey('customers.Customer', on_delete=models.CASCADE)
DoesNotExist
Cause: Querying for an object that does not exist in the database.
# Bad: Raises DoesNotExist
user = User.objects.get(id=999)
# Good: Handle missing objects
from django.shortcuts import get_object_or_404
user = get_object_or_404(User, id=999)
# Or use get_or_create
user, created = User.objects.get_or_create(
username='john',
defaults={'email': 'john@example.com'}
)
# Or wrap in try-except
try:
user = User.objects.get(id=999)
except User.DoesNotExist:
user = None
DisallowedHost
Cause: Request host not in ALLOWED_HOSTS setting.
# settings.py
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
'your-domain.com',
'.your-domain.com', # Wildcard for subdomains
]
NoReverseMatch
Cause: URL reverse lookup failed – URL name not found or wrong arguments.
# List all URL patterns
python manage.py show_urls # requires django-extensions
# Or manually inspect
python manage.py shell -c "from django.urls import get_resolver; print([p.name for p in get_resolver().url_patterns])"
# Check URL name matches exactly
from django.urls import reverse
url = reverse('app_name:view_name', args=[object_id])
url = reverse('app_name:view_name', kwargs={'pk': object_id})
Debugging Tools
Django Debug Toolbar
The most powerful visual debugging tool for Django development.
Installation:
pip install django-debug-toolbar
Configuration:
# settings.py (development only)
INSTALLED_APPS = [
# ...
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ... other middleware
]
INTERNAL_IPS = ['127.0.0.1']
# For Docker
DEBUG_TOOLBAR_CONFIG = {
'SHOW_TOOLBAR_CALLBACK': 'debug_toolbar.middleware.show_toolbar_with_docker',
}
# urls.py
from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns = [
# ... your URLs
] + debug_toolbar_urls()
Key panels:
- SQL: All database queries with timing and EXPLAIN
- Templates: Rendered templates and context variables
- Cache: Cache hits/misses
- Request: Headers, cookies, session data
- Signals: Django signals fired
Python Debugger (pdb/ipdb)
# Insert breakpoint in code
breakpoint() # Python 3.7+ (uses PYTHONBREAKPOINT env var)
# Or explicitly
import pdb; pdb.set_trace()
# For better experience
import ipdb; ipdb.set_trace()
Common pdb commands:
n(next): Execute next lines(step): Step into functionc(continue): Continue executionp variable: Print variable valuepp variable: Pretty printl(list): Show current codew(where): Show stack traceq(quit): Exit debugger
django-extensions shell_plus
pip install django-extensions
# Add to INSTALLED_APPS
INSTALLED_APPS = ['django_extensions', ...]
# Use enhanced shell with auto-imports
python manage.py shell_plus
# With IPython
python manage.py shell_plus --ipython
# Print SQL queries
python manage.py shell_plus --print-sql
Logging Configuration
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'file': {
'class': 'logging.FileHandler',
'filename': 'debug.log',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'INFO',
},
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG', # Shows all SQL queries
},
'myapp': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
}
Usage in code:
import logging
logger = logging.getLogger(__name__)
logger.debug('Detailed information')
logger.info('General information')
logger.warning('Warning message')
logger.error('Error occurred', exc_info=True) # Include traceback
logger.exception('Exception occurred') # Auto-includes traceback
SQL Query Logging
# In Django shell
from django.db import connection
from django.db import reset_queries
reset_queries()
# ... execute your queries ...
print(connection.queries)
# Or use QuerySet.explain()
queryset = User.objects.filter(is_active=True)
print(queryset.explain())
The Four Phases (Django-Specific)
Phase 1: Root Cause Investigation
Gather evidence systematically:
# 1. Check Django configuration
python manage.py check
python manage.py check --deploy # Production security checks
# 2. Review migration state
python manage.py showmigrations
python manage.py showmigrations --plan # Execution order
# 3. Inspect settings
python manage.py diffsettings # Compare with Django defaults
# 4. Check logs
tail -f debug.log
docker compose logs -f api # If using Docker
Examine the error traceback:
- Note the exception type (determines error category)
- Find the last line of YOUR code (not Django internals)
- Check variable values in the frame
Database state inspection:
# In shell
python manage.py shell
from myapp.models import MyModel
MyModel.objects.count()
MyModel.objects.filter(status='error').values()
Phase 2: Pattern Analysis
Compare with working patterns:
- Check similar working code: Find views/functions that work and compare
- Review Django documentation: Verify correct usage of APIs
- Check third-party package versions: Ensure compatibility
# Check installed versions
pip freeze | grep -i django
pip show django-rest-framework
Common pattern mismatches:
- Missing
returnin view functions - Wrong queryset method order
- Incorrect URL pattern syntax
- Missing model field attributes
Phase 3: Hypothesis and Testing
Write a failing test first:
# tests/test_debug.py
import pytest
from django.test import TestCase, Client
@pytest.mark.django_db
class TestBugFix(TestCase):
def test_reproduces_bug(self):
"""This test should fail until bug is fixed."""
client = Client()
response = client.get('/problematic-url/')
self.assertEqual(response.status_code, 200)
# Add assertions that currently fail
def test_edge_case(self):
"""Test the specific input that causes the bug."""
from myapp.services import problematic_function
result = problematic_function(edge_case_input)
self.assertEqual(result, expected_output)
Run tests in isolation:
# Run single test
pytest tests/test_debug.py::TestBugFix::test_reproduces_bug -v
# Run with verbose SQL output
pytest tests/test_debug.py -v --capture=no
# Run with debugger on failure
pytest tests/test_debug.py --pdb
# Run with coverage
pytest tests/test_debug.py --cov=myapp --cov-report=term-missing
Phase 4: Implementation
Implement the fix:
- Make minimal changes to fix the issue
- Ensure existing tests still pass
- Add new tests for the specific bug
- Document the fix in commit message
Verify the fix:
# Run all tests
pytest -v
# Run specific test file
pytest tests/test_affected_module.py -v
# Check for regressions
pytest tests/ -v --tb=short
# Verify in development server
python manage.py runserver
Post-fix checklist:
- All tests pass
- No new warnings introduced
-
python manage.py checkpasses - Related functionality manually tested
- Code reviewed
Quick Reference Commands
Django Management Commands
# System checks
python manage.py check # Run system checks
python manage.py check --deploy # Production deployment checks
python manage.py check --tag security # Security-specific checks
# Migrations
python manage.py showmigrations # List all migrations and status
python manage.py showmigrations --plan # Show execution order
python manage.py sqlmigrate app 0001 # Show SQL for migration
python manage.py makemigrations --dry-run # Preview migration creation
python manage.py migrate --plan # Show migration plan
# Settings
python manage.py diffsettings # Show non-default settings
python manage.py diffsettings --all # Show all settings
# Database
python manage.py dbshell # Database shell
python manage.py inspectdb # Generate models from database
# Shell
python manage.py shell # Django shell
python manage.py shell_plus # Enhanced shell (django-extensions)
python manage.py shell_plus --print-sql # Shell with SQL logging
# URLs
python manage.py show_urls # List all URLs (django-extensions)
# Cleanup
python manage.py clearsessions # Clear expired sessions
python manage.py flush # Clear database (DANGEROUS)
Quick Debugging Snippets
# Print all SQL queries in view
from django.db import connection
def my_view(request):
# ... view logic ...
for query in connection.queries:
print(query['sql'])
# Check if request is AJAX
request.headers.get('X-Requested-With') == 'XMLHttpRequest'
# Inspect request data
print(request.GET.dict())
print(request.POST.dict())
print(request.body)
print(dict(request.headers))
# Debug template context
# In template:
{% debug %}
# Or in view:
from django.template import engines
engine = engines['django']
template = engine.from_string("{{ debug }}")
Environment Debugging
# Check Python environment
which python
python --version
pip list
# Check Django version
python -c "import django; print(django.VERSION)"
# Check database connection
python manage.py dbshell -c "SELECT 1;"
# Check Redis connection (if using)
redis-cli ping
# Check Celery workers
celery -A config inspect active
celery -A config inspect stats