Django 検証ループ
PR の前、大きな変更後、デプロイ前に実行し、Django アプリケーションの品質とセキュリティを確保します。
実行タイミング
- Django プロジェクトのプルリクエストを作成する前
- モデルの大きな変更、マイグレーションの更新、依存関係のアップグレード後
- ステージングまたは本番環境へのデプロイ前の検証
- 環境全体 → リンター → テスト → セキュリティ → デプロイ準備パイプラインの実行
- マイグレーションの安全性とテストカバレッジの検証
フェーズ 1: 環境チェック
# Python バージョンの確認
python --version # プロジェクトの要件と一致している必要があります
# 仮想環境の確認
which python
pip list --outdated
# 環境変数の確認
python -c "import os; import environ; print('DJANGO_SECRET_KEY set' if os.environ.get('DJANGO_SECRET_KEY') else 'MISSING: DJANGO_SECRET_KEY')"
環境が正しく構成されていない場合は、停止して修正します。
フェーズ 2: コード品質とフォーマット
# 型チェック
mypy . --config-file pyproject.toml
# ruff によるリンター
ruff check . --fix
# black によるフォーマット
black . --check
black . # 自動修正
# インポートのソート
isort . --check-only
isort . # 自動修正
# Django 固有のチェック
python manage.py check --deploy
よくある問題:
- 公開関数の型ヒントの欠落
- PEP 8 フォーマット違反
- ソートされていないインポート
- 本番環境設定に残っているデバッグ設定
フェーズ 3: マイグレーション
# 未適用のマイグレーションを確認
python manage.py showmigrations
# 不足しているマイグレーションを作成
python manage.py makemigrations --check
# マイグレーション適用のドライラン
python manage.py migrate --plan
# マイグレーションを適用 (テスト環境)
python manage.py migrate
# マイグレーションの競合を確認
python manage.py makemigrations --merge # 競合がある場合のみ
レポート:
- 保留中のマイグレーション数
- マイグレーションの競合の有無
- マイグレーションがないモデル変更
フェーズ 4: テスト + カバレッジ
# pytest ですべてのテストを実行
pytest --cov=apps --cov-report=html --cov-report=term-missing --reuse-db
# 特定のアプリのテストを実行
pytest apps/users/tests/
# マーカーで実行
pytest -m "not slow" # 遅いテストをスキップ
pytest -m integration # 統合テストのみ
# カバレッジレポート
open htmlcov/index.html
レポート:
- 合計テスト数: X 成功、Y 失敗、Z スキップ
- 全体カバレッジ: XX%
- アプリ別カバレッジの内訳
カバレッジ目標:
| コンポーネント | 目標 |
|---|---|
| モデル | 90%+ |
| シリアライザ | 85%+ |
| ビュー | 80%+ |
| サービス | 90%+ |
| 全体 | 80%+ |
フェーズ 5: セキュリティスキャン
# 依存関係の脆弱性
pip-audit
safety check --full-report
# Django セキュリティチェック
python manage.py check --deploy
# Bandit セキュリティリンター
bandit -r . -f json -o bandit-report.json
# 機密情報のスキャン (gitleaks がインストールされている場合)
gitleaks detect --source . --verbose
# 環境変数のチェック
python -c "from django.core.exceptions import ImproperlyConfigured; from django.conf import settings; settings.DEBUG"
レポート:
- 脆弱性のある依存関係
- セキュリティ設定の問題
- 検出されたハードコードされた機密情報
- DEBUG モードの状態 (本番環境では False であるべき)
フェーズ 6: Django 管理コマンド
# モデルの問題をチェック
python manage.py check
# 静的ファイルを収集
python manage.py collectstatic --noinput --clear
# スーパーユーザーを作成 (テストに必要な場合)
echo "from apps.users.models import User; User.objects.create_superuser('[email protected]', 'admin')" | python manage.py shell
# データベースの整合性
python manage.py check --database default
# キャッシュの確認 (Redis を使用している場合)
python -c "from django.core.cache import cache; cache.set('test', 'value', 10); print(cache.get('test'))"
フェーズ 7: パフォーマンスチェック
# Django Debug Toolbar の出力 (N+1 クエリをチェック)
# DEBUG=True の開発モードで実行し、ページにアクセス
# SQL パネルで重複クエリを確認
# クエリ数分析
django-admin debugsqlshell # django-debug-sqlshell がインストールされている場合
# 欠落しているインデックスをチェック
python manage.py shell << EOF
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT table_name, index_name FROM information_schema.statistics WHERE table_schema = 'public'")
print(cursor.fetchall())
EOF
レポート:
- ページあたりのクエリ数 (通常のページでは 50 未満であるべき)
- 欠落しているデータベースインデックス
- 検出された重複クエリ
フェーズ 8: 静的アセット
# npm 依存関係を確認 (npm を使用している場合)
npm audit
npm audit fix
# 静的ファイルをビルド (webpack/vite を使用している場合)
npm run build
# 静的ファイルを確認
ls -la staticfiles/
python manage.py findstatic css/style.css
フェーズ 9: 設定レビュー
# Python シェルで設定を確認
python manage.py shell << EOF
from django.conf import settings
import os
# 重要なチェック
checks = {
'DEBUG が False': not settings.DEBUG,
'SECRET_KEY が設定されている': bool(settings.SECRET_KEY and len(settings.SECRET_KEY) > 30),
'ALLOWED_HOSTS が設定されている': len(settings.ALLOWED_HOSTS) > 0,
'HTTPS が有効': getattr(settings, 'SECURE_SSL_REDIRECT', False),
'HSTS が有効': getattr(settings, 'SECURE_HSTS_SECONDS', 0) > 0,
'データベースが設定されている': settings.DATABASES['default']['ENGINE'] != 'django.db.backends.sqlite3',
}
for check, result in checks.items():
status = '✓' if result else '✗'
print(f"{status} {check}")
EOF
フェーズ 10: ログ設定
# ログ出力をテスト
python manage.py shell << EOF
import logging
logger = logging.getLogger('django')
logger.warning('Test warning message')
logger.error('Test error message')
EOF
# ログファイルを確認 (設定されている場合)
tail -f /var/log/django/django.log
フェーズ 11: API ドキュメント (DRF を使用している場合)
# スキーマを生成
python manage.py generateschema --format openapi-json > schema.json
# スキーマを検証
# schema.json が有効な JSON であることを確認
python -c "import json; json.load(open('schema.json'))"
# Swagger UI にアクセス (drf-yasg を使用している場合)
# ブラウザで http://localhost:8000/swagger/ にアクセス
フェーズ 12: 差分レビュー
# 差分統計を表示
git diff --stat
# 実際の変更を表示
git diff
# 変更されたファイルを表示
git diff --name-only
# よくある問題をチェック
git diff | grep -i "todo\|fixme\|hack\|xxx"
git diff | grep "print(" # デバッグ文
git diff | grep "DEBUG = True" # デバッグモード
git diff | grep "import pdb" # デバッガ
チェックリスト:
- デバッグ文 (print, pdb, breakpoint()) がないこと
- 重要なコードに TODO/FIXME コメントがないこと
- ハードコードされた機密情報や認証情報がないこと
- モデル変更に対してデータベースマイグレーションが含まれていること
- 設定変更が文書化されていること
- 外部呼び出しに対するエラーハンドリングが実装されていること
- トランザクション管理が必要な箇所に実装されていること
出力テンプレート
DJANGO 検証レポート
==========================
フェーズ 1: 環境チェック
✓ Python 3.11.5
✓ 仮想環境がアクティブ
✓ すべての環境変数が設定済み
フェーズ 2: コード品質
✓ mypy: 型エラーなし
✗ ruff: 3 件の問題を検出 (自動修正済み)
✓ black: フォーマット問題なし
✓ isort: インポートが正しくソート済み
✓ manage.py check: 問題なし
フェーズ 3: マイグレーション
✓ 未適用のマイグレーションなし
✓ マイグレーションの競合なし
✓ すべてのモデルにマイグレーションあり
フェーズ 4: テスト + カバレッジ
テスト: 247 成功、0 失敗、5 スキップ
カバレッジ:
全体: 87%
users: 92%
products: 89%
orders: 85%
payments: 91%
フェーズ 5: セキュリティスキャン
✗ pip-audit: 2 件の脆弱性を検出 (修正が必要)
✓ safety check: 問題なし
✓ bandit: セキュリティ問題なし
✓ 機密情報は検出されず
✓ DEBUG = False
フェーズ 6: Django コマンド
✓ collectstatic 完了
✓ データベースの整合性 OK
✓ キャッシュバックエンドに接続可能
フェーズ 7: パフォーマンス
✓ N+1 クエリは検出されず
✓ データベースインデックスが設定済み
✓ クエリ数は許容範囲内
フェーズ 8: 静的アセット
✓ npm audit: 脆弱性なし
✓ アセットのビルド成功
✓ 静的ファイルが収集済み
フェーズ 9: 設定
✓ DEBUG = False
✓ SECRET_KEY が設定済み
✓ ALLOWED_HOSTS が設定済み
✓ HTTPS が有効
✓ HSTS が有効
✓ データベースが設定済み
フェーズ 10: ログ
✓ ログが設定済み
✓ ログファイルが書き込み可能
フェーズ 11: API ドキュメント
✓ スキーマが生成済み
✓ Swagger UI にアクセス可能
フェーズ 12: 差分レビュー
変更ファイル数: 12
+450, -120 行
✓ デバッグ文なし
✓ ハードコードされた機密情報なし
✓ マイグレーションが含まれている
推奨事項: 警告: デプロイ前に pip-audit の脆弱性を修正してください
次のステップ:
1. 脆弱性のある依存関係を更新
2. セキュリティスキャンを再実行
3. 最終テストのためにステージングにデプロイ
デプロイ前チェックリスト
- すべてのテストが合格
- カバレッジ ≥ 80%
- セキュリティ脆弱性なし
- 未適用のマイグレーションなし
- 本番環境設定で DEBUG = False
- SECRET_KEY が正しく設定済み
- ALLOWED_HOSTS が正しく設定済み
- データベースのバックアップが有効
- 静的ファイルが収集され、配信されている
- ログが設定され、動作している
- エラーモニタリング (Sentry など) が設定済み
- CDN が設定済み (該当する場合)
- Redis/キャッシュバックエンドが設定済み
- Celery ワーカーが実行中 (該当する場合)
- HTTPS/SSL が設定済み
- 環境変数が文書化されている
継続的インテグレーション
GitHub Actions の例
# .github/workflows/django-verification.yml
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@v3
クイックリファレンス
| チェック | コマンド |
|---|---|
| 環境 | python --version |
| 型チェック | mypy . |
| リンター | ruff check . |
| フォーマット | black . --check |
| マイグレーション | python manage.py makemigrations --check |
| テスト | pytest --cov=apps |
| セキュリティ | pip-audit && bandit -r . |
| Django チェック | python manage.py check --deploy |
| collectstatic | python manage.py collectstatic --noinput |
| 差分統計 | git diff --stat |
注意: 自動検証は一般的な問題を検出しますが、手動によるコードレビューとステージング環境でのテストを代替するものではありません。