ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
Django + Ajax POST の全体像
Django で Ajax から POST する際、最大の関門は CSRF (Cross-Site Request Forgery) 保護です。Django は POST / PUT / PATCH / DELETE に対し毎リクエスト CSRF Tokenを要求します。Token を付け忘れると HTTP 403 Forbidden で弾かれます。
全体フロー
[ Browser ] [ Django ]
│ │
│ GET /form/ (HTML + csrftoken Cookie) │
│ ◀────────────────────────────────────│
│ │
│ POST /api/save/ │
│ X-CSRFToken: <token> │
│ Content-Type: application/json │
│ { "name": "Taro" } │
│ ────────────────────────────────────▶ │
│ │ ← CSRF middleware が検証
│ │ ← views.py で処理
│ 200 { "ok": true, "id": 42 } │
│ ◀────────────────────────────────────│
手順1: CSRF Token をテンプレートに埋め込む
{# templates/form.html #}
<form id="myForm">
{% csrf_token %}
<input name="name">
<input name="email">
<button type="submit">送信</button>
</form>
<script>
// {% csrf_token %} は次のような hidden input を生成
// <input type="hidden" name="csrfmiddlewaretoken" value="abc123...">
</script>
手順2: jQuery $.ajax での POST
// CSRF Token を Cookie から取得
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
const csrftoken = getCookie('csrftoken');
// $.ajaxSetup でグローバルに設定(推奨)
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) {
xhr.setRequestHeader('X-CSRFToken', csrftoken);
}
}
});
// POST 実行
$.ajax({
method: 'POST',
url: '/api/save/',
contentType: 'application/json',
data: JSON.stringify({
name: $('input[name=name]').val(),
email: $('input[name=email]').val(),
}),
success: function (resp) {
console.log('OK', resp);
},
error: function (xhr) {
console.error('NG', xhr.status, xhr.responseText);
}
});
手順3: fetch API(jQuery 不使用)
// CSRF Token 取得
function getCookie(name) {
const m = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
return m ? decodeURIComponent(m.pop()) : '';
}
async function postJSON(url, data) {
const res = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken'),
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// 利用
document.getElementById('myForm').addEventListener('submit', async (e) => {
e.preventDefault();
try {
const json = await postJSON('/api/save/', {
name: e.target.name.value,
email: e.target.email.value,
});
console.log('OK', json);
} catch (err) {
console.error(err);
}
});
手順4: Django views.py で受ける(FBV)
# views.py
import json
from django.http import JsonResponse, HttpResponseBadRequest
from django.views.decorators.http import require_POST
@require_POST
def api_save(request):
# JSON ボディ
try:
payload = json.loads(request.body.decode('utf-8'))
except json.JSONDecodeError:
return HttpResponseBadRequest('invalid JSON')
name = (payload.get('name') or '').strip()
email = (payload.get('email') or '').strip()
if not name or not email:
return JsonResponse({'ok': False, 'errors': {'name': '必須', 'email': '必須'}}, status=400)
# DB 保存
from .models import Contact
obj = Contact.objects.create(name=name, email=email)
return JsonResponse({'ok': True, 'id': obj.id})
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('api/save/', views.api_save, name='api_save'),
]
FormData(multipart)で受ける場合
@require_POST
def api_upload(request):
name = request.POST.get('name', '').strip()
file = request.FILES.get('avatar')
if not file:
return JsonResponse({'ok': False, 'msg': 'file required'}, status=400)
# ファイル保存
from django.core.files.storage import default_storage
path = default_storage.save(f'avatars/{file.name}', file)
return JsonResponse({'ok': True, 'path': path})// FormData は Content-Type を自動設定(境界文字列付き)
const fd = new FormData();
fd.append('name', 'Taro');
fd.append('avatar', fileInput.files[0]);
await fetch('/api/upload/', {
method: 'POST',
body: fd,
headers: { 'X-CSRFToken': getCookie('csrftoken') },
});
CSRF Token が無いとどうなるか
# レスポンス
HTTP/1.1 403 Forbidden
<h1>Forbidden (403)</h1>
<p>CSRF verification failed. Request aborted.</p>
# settings.py
CSRF_COOKIE_HTTPONLY = False # JS から読みたいなら False(既定)
CSRF_COOKIE_SAMESITE = 'Lax' # クロスサイトでは 'None' + Secure
# 例外的に CSRF をスキップしたい view(外部 Webhook 等)
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def webhook(request):
...
CBV(Class-Based View)で書く
from django.views import View
from django.http import JsonResponse
import json
class SaveAPI(View):
def post(self, request):
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return JsonResponse({'ok': False, 'msg': 'invalid JSON'}, status=400)
# ...
return JsonResponse({'ok': True})
# urls.py
path('api/save/', SaveAPI.as_view()),
Django REST Framework との比較
# api/views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def save(request):
name = request.data.get('name')
email = request.data.get('email')
return Response({'ok': True, 'name': name})
# ModelSerializer + ViewSet が本命
from rest_framework import viewsets, serializers
from .models import Contact
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = '__all__'
class ContactViewSet(viewsets.ModelViewSet):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('contacts', ContactViewSet)
urlpatterns += router.urls
DRF の場合、デフォルトの SessionAuthentication は CSRF を要求します(ブラウザから叩く時)。TokenAuthentication / JWT は CSRF 不要。
Laravel Sanctum との比較
| 項目 | Django | Laravel Sanctum |
|---|---|---|
| CSRF | X-CSRFToken 必須 | X-XSRF-TOKEN 必須(SPA) |
| セッション認証 | 標準 | Sanctum::actingAs |
| API Token | DRF Token / JWT 追加 | 標準(Personal Access Token) |
| SPA テンプレート | Templates + 部分 Ajax | Vue/React + Inertia |
セキュリティ設定
# settings.py
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
SECURE_HSTS_SECONDS = 60 * 60 * 24 * 365
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# 本番のみ
CSRF_TRUSTED_ORIGINS = ['https://app.example.com']
CORS_ALLOWED_ORIGINS = ['https://app.example.com'] # django-cors-headers
よくあるトラブル
| 症状 | 原因 | 対処 |
|---|---|---|
| 403 Forbidden CSRF failed | X-CSRFToken 未送信 / Token 不一致 | Cookie から取得 → header にセット |
| POST が GET 扱いされる | method: 'post' なのに body 未送信 | Content-Type 設定 + body 確認 |
| CORS エラー | クロスオリジン | django-cors-headers 導入 |
| JSON が空 | request.POST で取得 | json.loads(request.body) を使う |
| 500 internal error | views で例外 | DEBUG=True で原因確認 |
FAQ
Q: SPA から Ajax POST する時の CSRF はどうする?
A: ログイン後に Cookie csrftoken が払い出されます。JS で読み X-CSRFToken ヘッダに付ければ通ります。CORS では credentials: 'include'。
Q: @csrf_exempt はどんな時に使う?
A: 外部からの Webhook 受信(Stripe / GitHub 等)で署名検証を別に行う場合。通常の自社フロントには使わないでください。
Q: ファイル + JSON を同時に送りたい
A: FormData でフィールドを追加し、JSON はテキスト化して fd.append('meta', JSON.stringify(data))。Django 側で json.loads(request.POST['meta'])。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- 環境構築とプロジェクト/アプリの作成
- MVC(MVT)のそれぞれの使い方と説明
- データベースへの接続と操作
- Django Administration
- git管理
- エラー一覧
- バージョンの確認方法
- ログ出力方法
- SQLのログ出力方法
- ログのローテート設定
- settings.pyの定数にアクセスする方法
- 本番環境へのインストールとアプリのデプロイ(apache編)
- 本番環境へのインストールとアプリのデプロイ(nginx編)
- djangoアプリの本番の開始URLを変更する
- 静的(static)ファイルの置き場所と読み込み(画像、css、js )
- CSRFトークンをAjaxで使用する方法
- ajaxの使用例(POST編)
- ファイルのアップロードとファイルの名前
- クイックスタート/チュートリアル
- ログイン機能
- テンプレート側のログイン判定
- ビュー側のログイン判定
- 管理者ユーザーの作成/判定と管理画面
- モデルのjson化とレスポンス
- runserverでポートを指定する方法
- cronによるバッチ実行
- テンプレートで利用する共通のcontextを定義する方法
- プログラムが本番サーバーで反映されない場合の対処法
- APIの作成
- cron用コマンド・ファイルの作成
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- IPv6とは|128bitアドレス・コロン16進表記/::省略・リンクローカル・SLAAC・デュアルスタック NEW 2026-06-22 12:34:44
- VPNとは|暗号トンネル・サイト間/リモートアクセス・IPsec/SSL-VPN/WireGuardを解説 NEW 2026-06-22 12:19:10
- MAC アドレスフィルタリングの仕組みと限界 | ネットワーク入門 NEW 2026-06-22 12:19:10
- WebRTC とは ブラウザ間 P2P の音声・映像・データ通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- gRPC とは HTTP/2 + Protocol Buffers の高速 RPC | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/3 (QUIC) とは UDP ベースの低遅延 Web 通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/2 とは 多重化・HPACK・バイナリフレーム | ネットワーク入門 NEW 2026-06-22 12:17:25
- Web通信プロトコル入門 HTTP/2・HTTP/3・WebSocket・gRPC・WebRTC | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebSocket とは 全二重リアルタイム通信 ws/wss | ネットワーク入門 NEW 2026-06-22 12:17:25
- ファイアウォールとは|パケットフィルタ・ステートフル・DMZ・次世代FW(L4/L7)を解説 NEW 2026-06-22 12:17:24
- iptables/nftablesとは|テーブル・チェーン・ルール例・永続化をLinux視点で解説 NEW 2026-06-22 12:17:24
- HAProxy とは frontend/backend と設定例 | ネットワーク入門 NEW 2026-06-22 12:17:24
- 証明書と認証局(CA)とは|X.509・信頼チェーン・DV/OV/EV・失効(CRL/OCSP)を解説 NEW 2026-06-22 12:17:24
- CDN とは エッジキャッシュ・TTL・Cloudflare/CloudFront | ネットワーク入門 NEW 2026-06-22 12:17:24
- TLS/SSLの仕組み|ハンドシェイク・暗号スイート・前方秘匿性・証明書検証をわかりやすく解説 NEW 2026-06-22 12:17:24
コメントを削除してもよろしいでしょうか?