django-verification
Verification loop for Django projects: migrations, linting, tests with coverage, security scans, and deployment readiness checks before release or PR.
Django Verification Loop
Run before PRs, after major changes, and pre-deploy to ensure Django application quality and security.
When to Activate
- Before opening a pull request for a Django project
- After major model changes, migration updates, or dependency upgrades
- Pre-deployment verification for staging or production
- Running full environment → lint → test → security → deploy readiness pipeline
- Validating migration safety and test coverage
Phase 1: Environment Check
# Verify Python versionpython --version # Should match project requirements
# Check virtual environmentwhich pythonpip list --outdated
# Verify environment variablespython -c "import os; import environ; print('DJANGO_SECRET_KEY set' if os.environ.get('DJANGO_SECRET_KEY') else 'MISSING: DJANGO_SECRET_KEY')"If environment is misconfigured, stop and fix.
Phase 2: Code Quality & Formatting
# Type checkingmypy . --config-file pyproject.toml
# Linting with ruffruff check . --fix
# Formatting with blackblack . --checkblack . # Auto-fix
# Import sortingisort . --check-onlyisort . # Auto-fix
# Django-specific checkspython manage.py check --deployCommon issues:
- Missing type hints on public functions
- PEP 8 formatting violations
- Unsorted imports
- Debug settings left in production configuration
Phase 3: Migrations
# Check for unapplied migrationspython manage.py showmigrations
# Create missing migrationspython manage.py makemigrations --check
# Dry-run migration applicationpython manage.py migrate --plan
# Apply migrations (test environment)python manage.py migrate
# Check for migration conflictspython manage.py makemigrations --merge # Only if conflicts existReport:
- Number of pending migrations
- Any migration conflicts
- Model changes without migrations
Phase 4: Tests + Coverage
# Run all tests with pytestpytest --cov=apps --cov-report=html --cov-report=term-missing --reuse-db
# Run specific app testspytest apps/users/tests/
# Run with markerspytest -m "not slow" # Skip slow testspytest -m integration # Only integration tests
# Coverage reportopen htmlcov/index.htmlReport:
- Total tests: X passed, Y failed, Z skipped
- Overall coverage: XX%
- Per-app coverage breakdown
Coverage targets:
| Component | Target |
|---|---|
| Models | 90%+ |
| Serializers | 85%+ |
| Views | 80%+ |
| Services | 90%+ |
| Overall | 80%+ |
Phase 5: Security Scan
# Dependency vulnerabilitiespip-auditsafety check --full-report
# Django security checkspython manage.py check --deploy
# Bandit security linterbandit -r . -f json -o bandit-report.json
# Secret scanning (if gitleaks is installed)gitleaks detect --source . --verbose
# Environment variable checkpython -c "from django.core.exceptions import ImproperlyConfigured; from django.conf import settings; settings.DEBUG"Report:
- Vulnerable dependencies found
- Security configuration issues
- Hardcoded secrets detected
- DEBUG mode status (should be False in production)
Phase 6: Django Management Commands
# Check for model issuespython manage.py check
# Collect static filespython manage.py collectstatic --noinput --clear
# Create superuser (if needed for tests)echo "from apps.users.models import User; User.objects.create_superuser('admin@example.com', 'admin')" | python manage.py shell
# Database integritypython manage.py check --database default
# Cache verification (if using Redis)python -c "from django.core.cache import cache; cache.set('test', 'value', 10); print(cache.get('test'))"Phase 7: Performance Checks
# Django Debug Toolbar output (check for N+1 queries)# Run in dev mode with DEBUG=True and access a page# Look for duplicate queries in SQL panel
# Query count analysisdjango-admin debugsqlshell # If django-debug-sqlshell installed
# Check for missing indexespython manage.py shell << EOFfrom django.db import connectionwith connection.cursor() as cursor: cursor.execute("SELECT table_name, index_name FROM information_schema.statistics WHERE table_schema = 'public'") print(cursor.fetchall())EOFReport:
- Number of queries per page (should be < 50 for typical pages)
- Missing database indexes
- Duplicate queries detected
Phase 8: Static Assets
# Check for npm dependencies (if using npm)npm auditnpm audit fix
# Build static files (if using webpack/vite)npm run build
# Verify static filesls -la staticfiles/python manage.py findstatic css/style.cssPhase 9: Configuration Review
# Run in Python shell to verify settingspython manage.py shell << EOFfrom django.conf import settingsimport os
# Critical checkschecks = { 'DEBUG is False': not settings.DEBUG, 'SECRET_KEY set': bool(settings.SECRET_KEY and len(settings.SECRET_KEY) > 30), 'ALLOWED_HOSTS set': len(settings.ALLOWED_HOSTS) > 0, 'HTTPS enabled': getattr(settings, 'SECURE_SSL_REDIRECT', False), 'HSTS enabled': getattr(settings, 'SECURE_HSTS_SECONDS', 0) > 0, 'Database configured': settings.DATABASES['default']['ENGINE'] != 'django.db.backends.sqlite3',}
for check, result in checks.items(): status = '✓' if result else '✗' print(f"{status} {check}")EOFPhase 10: Logging Configuration
# Test logging outputpython manage.py shell << EOFimport logginglogger = logging.getLogger('django')logger.warning('Test warning message')logger.error('Test error message')EOF
# Check log files (if configured)tail -f /var/log/django/django.logPhase 11: API Documentation (if DRF)
# Generate schemapython manage.py generateschema --format openapi-json > schema.json
# Validate schema# Check if schema.json is valid JSONpython -c "import json; json.load(open('schema.json'))"
# Access Swagger UI (if using drf-yasg)# Visit http://localhost:8000/swagger/ in browserPhase 12: Diff Review
# Show diff statisticsgit diff --stat
# Show actual changesgit diff
# Show changed filesgit diff --name-only
# Check for common issuesgit diff | grep -i "todo\|fixme\|hack\|xxx"git diff | grep "print(" # Debug statementsgit diff | grep "DEBUG = True" # Debug modegit diff | grep "import pdb" # DebuggerChecklist:
- No debugging statements (print, pdb, breakpoint())
- No TODO/FIXME comments in critical code
- No hardcoded secrets or credentials
- Database migrations included for model changes
- Configuration changes documented
- Error handling present for external calls
- Transaction management where needed
Output Template
DJANGO VERIFICATION REPORT==========================
Phase 1: Environment Check ✓ Python 3.11.5 ✓ Virtual environment active ✓ All environment variables set
Phase 2: Code Quality ✓ mypy: No type errors ✗ ruff: 3 issues found (auto-fixed) ✓ black: No formatting issues ✓ isort: Imports properly sorted ✓ manage.py check: No issues
Phase 3: Migrations ✓ No unapplied migrations ✓ No migration conflicts ✓ All models have migrations
Phase 4: Tests + Coverage Tests: 247 passed, 0 failed, 5 skipped Coverage: Overall: 87% users: 92% products: 89% orders: 85% payments: 91%
Phase 5: Security Scan ✗ pip-audit: 2 vulnerabilities found (fix required) ✓ safety check: No issues ✓ bandit: No security issues ✓ No secrets detected ✓ DEBUG = False
Phase 6: Django Commands ✓ collectstatic completed ✓ Database integrity OK ✓ Cache backend reachable
Phase 7: Performance ✓ No N+1 queries detected ✓ Database indexes configured ✓ Query count acceptable
Phase 8: Static Assets ✓ npm audit: No vulnerabilities ✓ Assets built successfully ✓ Static files collected
Phase 9: Configuration ✓ DEBUG = False ✓ SECRET_KEY configured ✓ ALLOWED_HOSTS set ✓ HTTPS enabled ✓ HSTS enabled ✓ Database configured
Phase 10: Logging ✓ Logging configured ✓ Log files writable
Phase 11: API Documentation ✓ Schema generated ✓ Swagger UI accessible
Phase 12: Diff Review Files changed: 12 +450, -120 lines ✓ No debug statements ✓ No hardcoded secrets ✓ Migrations included
RECOMMENDATION: WARNING: Fix pip-audit vulnerabilities before deploying
NEXT STEPS:1. Update vulnerable dependencies2. Re-run security scan3. Deploy to staging for final testingPre-Deployment Checklist
- All tests passing
- Coverage ≥ 80%
- No security vulnerabilities
- No unapplied migrations
- DEBUG = False in production settings
- SECRET_KEY properly configured
- ALLOWED_HOSTS set correctly
- Database backups enabled
- Static files collected and served
- Logging configured and working
- Error monitoring (Sentry, etc.) configured
- CDN configured (if applicable)
- Redis/cache backend configured
- Celery workers running (if applicable)
- HTTPS/SSL configured
- Environment variables documented
Continuous Integration
GitHub Actions Example
name: Django Verification
on: [push, pull_request]
jobs: verify: runs-on: ubuntu-latest services: postgres: image: postgres:14 env: POSTGRES_PASSWORD: postgres options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps: - uses: actions/checkout@v3
- name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11'
- name: Cache pip uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- name: Install dependencies run: | pip install -r requirements.txt pip install ruff black mypy pytest pytest-django pytest-cov bandit safety pip-audit
- name: Code quality checks run: | ruff check . black . --check isort . --check-only mypy .
- name: Security scan run: | bandit -r . -f json -o bandit-report.json safety check --full-report pip-audit
- name: Run tests env: DATABASE_URL: postgres://postgres:postgres@localhost:5432/test DJANGO_SECRET_KEY: test-secret-key run: | pytest --cov=apps --cov-report=xml --cov-report=term-missing
- name: Upload coverage uses: codecov/codecov-action@v3Quick Reference
| Check | Command |
|---|---|
| Environment | python --version |
| Type checking | mypy . |
| Linting | ruff check . |
| Formatting | black . --check |
| Migrations | python manage.py makemigrations --check |
| Tests | pytest --cov=apps |
| Security | pip-audit && bandit -r . |
| Django check | python manage.py check --deploy |
| Collectstatic | python manage.py collectstatic --noinput |
| Diff stats | git diff --stat |
Remember: Automated verification catches common issues but doesn’t replace manual code review and testing in staging environment.