DjangoでREST APIを作る
基本からDjango REST Frameworkまで
DjangoでREST APIを構築する方法を解説。JsonResponseによるシンプルなAPIから、Django REST Frameworkを使った本格的なAPI開発まで学べます。
こんな人向けの記事です
- DjangoでAPIを作りたい
- Django REST Frameworkを使い始めたい
- Serializerやパーミッションの仕組みを理解したい
Step 1REST APIとは
REST(Representational State Transfer)APIとは、HTTPメソッドを使ってリソースを操作する設計スタイルのWebAPIです。Webブラウザ向けにHTMLを返すのではなく、JSON形式のデータを返すことで、フロントエンド(React、Vue等)やモバイルアプリなど様々なクライアントからデータをやり取りできます。
REST APIでは、URLが「リソース(データ)」を表し、HTTPメソッドが「操作」を表します。
例えば /api/articles/ というURLに対して、GETで取得、POSTで作成、のように操作を分けます。
| HTTPメソッド | 操作 | URL例 | 説明 |
|---|---|---|---|
GET | 取得(一覧) | /api/articles/ | 記事の一覧を取得 |
GET | 取得(詳細) | /api/articles/1/ | ID=1の記事を取得 |
POST | 作成 | /api/articles/ | 新しい記事を作成 |
PUT | 全体更新 | /api/articles/1/ | ID=1の記事を全体更新 |
PATCH | 部分更新 | /api/articles/1/ | ID=1の記事を部分更新 |
DELETE | 削除 | /api/articles/1/ | ID=1の記事を削除 |
REST APIのレスポンスは通常JSON形式で返されます。
{
"id": 1,
"title": "Djangoの基本",
"content": "Djangoは...",
"is_published": true,
"created_at": "2026-02-18T10:30:00Z"
}
従来のDjangoはサーバー側でHTMLを生成して返す方式(テンプレートレンダリング)でした。しかし、フロントエンドとバックエンドを分離する現代の開発スタイルでは、バックエンドはデータ(JSON)だけを返し、画面の描画はフロントエンドが担当します。この「データだけ返すバックエンド」がREST APIです。
Step 2Django JsonResponseでシンプルなAPIを作る
Django REST Frameworkを使わなくても、Djangoの標準機能だけでシンプルなAPIは作れます。まずはJsonResponseを使った方法を見てみましょう。
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
is_published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import Article
# 記事一覧を取得するAPI
def article_list(request):
if request.method == 'GET':
articles = Article.objects.filter(is_published=True)
data = []
for article in articles:
data.append({
'id': article.id,
'title': article.title,
'content': article.content,
'created_at': article.created_at.isoformat(),
})
return JsonResponse({'articles': data})
# 記事詳細を取得するAPI
def article_detail(request, pk):
try:
article = Article.objects.get(pk=pk)
except Article.DoesNotExist:
return JsonResponse({'error': '記事が見つかりません'}, status=404)
if request.method == 'GET':
data = {
'id': article.id,
'title': article.title,
'content': article.content,
'created_at': article.created_at.isoformat(),
}
return JsonResponse(data)
# 記事を作成するAPI
@csrf_exempt # 本番では適切なCSRF対策を行う
def article_create(request):
if request.method == 'POST':
body = json.loads(request.body)
article = Article.objects.create(
title=body['title'],
content=body['content'],
is_published=body.get('is_published', False),
)
return JsonResponse({
'id': article.id,
'title': article.title,
}, status=201)
from django.urls import path
from . import views
urlpatterns = [
path('api/articles/', views.article_list, name='article-list'),
path('api/articles/<int:pk>/', views.article_detail, name='article-detail'),
path('api/articles/create/', views.article_create, name='article-create'),
]
- シリアライズ(モデル→JSON変換)を毎回手動で書く必要がある
- バリデーション処理を自分で実装しなければならない
- 認証・パーミッション機能がない
- HTTPメソッドの分岐を手動で書く必要がある
- APIドキュメントの自動生成ができない
これらの問題を解決するのがDjango REST Framework(DRF)です。
Step 3Django REST Frameworkの導入
Django REST Framework(DRF)は、DjangoでREST APIを効率的に構築するためのサードパーティライブラリです。シリアライズ、バリデーション、認証、パーミッションなどAPIに必要な機能が一通り揃っています。
pip install djangorestframework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 追加
'myapp',
]
DRFでは主に以下の3つのコンポーネントを使ってAPIを構築します。
| コンポーネント | 役割 | 対応するDjango機能 |
|---|---|---|
Serializer | モデル ⇔ JSON の変換・バリデーション | Form / ModelForm |
APIView / ViewSet | リクエスト処理・レスポンス返却 | View / CBV |
Router | URL自動生成 | urls.py の手動定義 |
DRFを導入すると、Browsable API(ブラウザで操作できるAPI画面)が使えるようになります。これは開発中のAPIテストに非常に便利です。
REST_FRAMEWORK = {
# レスポンスのデフォルトフォーマット
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer', # 開発用
],
# ページネーション
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
Step 4Serializerの基本
Serializer(シリアライザー)は、モデルインスタンスをJSONに変換したり、逆にリクエストデータをモデルインスタンスに変換する役割を持ちます。DjangoのFormに近い概念です。
from rest_framework import serializers
from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['id', 'title', 'content', 'is_published', 'created_at']
read_only_fields = ['id', 'created_at']
| Meta属性 | 説明 |
|---|---|
model | 対応するモデルクラス |
fields | APIに含めるフィールド('__all__'で全フィールド) |
read_only_fields | 読み取り専用フィールド(作成・更新時に無視) |
exclude | 除外するフィールド(fieldsの代わりに使用) |
Serializerを使うとバリデーションも簡単に追加できます。
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['id', 'title', 'content', 'is_published', 'created_at']
read_only_fields = ['id', 'created_at']
# フィールド単位のバリデーション
def validate_title(self, value):
if len(value) < 3:
raise serializers.ValidationError('タイトルは3文字以上にしてください')
return value
# 複数フィールドにまたがるバリデーション
def validate(self, data):
if data.get('is_published') and not data.get('content'):
raise serializers.ValidationError('公開する記事には本文が必要です')
return data
Serializerを使ったシリアライズとデシリアライズの流れは以下の通りです。
# シリアライズ(モデル → JSON用dict)
article = Article.objects.first()
serializer = ArticleSerializer(article)
print(serializer.data)
# {'id': 1, 'title': '...', 'content': '...', ...}
# デシリアライズ(リクエストデータ → モデル)
data = {'title': '新しい記事', 'content': '本文...', 'is_published': True}
serializer = ArticleSerializer(data=data)
serializer.is_valid(raise_exception=True) # バリデーション実行
serializer.save() # DBに保存
リレーション先のデータも含めてJSONに変換できます。
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['id', 'text', 'created_at']
class ArticleDetailSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ['id', 'title', 'content', 'is_published', 'comments']
Step 5ViewSetとRouter
DRFには複数のビューの書き方がありますが、最も効率的なのがViewSet + Routerの組み合わせです。CRUDの処理とURLルーティングを最小限のコードで実現できます。
DRFでは用途に応じて複数のビュークラスが用意されています。上から順に抽象度が上がり、コード量が減ります。
| クラス | 特徴 | ユースケース |
|---|---|---|
APIView | 最も基本的。HTTPメソッドを手動で実装 | カスタムロジックが多いAPI |
GenericAPIView + Mixin | 一覧・詳細・作成などをMixinで追加 | 標準的なCRUDの一部だけ必要な場合 |
ModelViewSet | CRUD全操作を自動提供 | 標準的なCRUD API |
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Article
from .serializers import ArticleSerializer
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.filter(is_published=True)
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.filter(is_published=True)
serializer_class = ArticleSerializer
たったこれだけで、一覧取得・詳細取得・作成・更新・削除の全APIが自動で作られます。
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet
router = DefaultRouter()
router.register('articles', ArticleViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Routerが自動生成するURLは以下の通りです。
| URL | メソッド | アクション |
|---|---|---|
/api/articles/ | GET | 一覧取得(list) |
/api/articles/ | POST | 作成(create) |
/api/articles/{id}/ | GET | 詳細取得(retrieve) |
/api/articles/{id}/ | PUT | 全体更新(update) |
/api/articles/{id}/ | PATCH | 部分更新(partial_update) |
/api/articles/{id}/ | DELETE | 削除(destroy) |
ViewSetに独自のエンドポイントを追加するには @action デコレータを使います。
from rest_framework.decorators import action
from rest_framework.response import Response
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# /api/articles/published/ でアクセス可能
@action(detail=False, methods=['get'])
def published(self, request):
published = self.queryset.filter(is_published=True)
serializer = self.get_serializer(published, many=True)
return Response(serializer.data)
# /api/articles/{id}/publish/ でアクセス可能
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
article = self.get_object()
article.is_published = True
article.save()
return Response({'status': '公開しました'})
Step 6認証とパーミッション
APIを公開する際、誰がアクセスできるか(認証)と何ができるか(パーミッション)の設定は必須です。DRFには豊富な認証・パーミッション機能が組み込まれています。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
| 認証クラス | 方式 | ユースケース |
|---|---|---|
SessionAuthentication | Djangoのセッション | ブラウザからのアクセス |
TokenAuthentication | トークンベース | モバイルアプリ・外部API |
BasicAuthentication | Basic認証 | テスト・開発時 |
TokenAuthenticationを使う場合の設定手順です。
# settings.py に追加
INSTALLED_APPS = [
...
'rest_framework.authtoken', # 追加
]
# マイグレーション実行
# python manage.py migrate
# トークン発行(Django shell)
# from rest_framework.authtoken.models import Token
# from django.contrib.auth.models import User
# user = User.objects.get(username='admin')
# token = Token.objects.create(user=user)
# print(token.key) # このトークンをクライアントに渡す
# curlでトークン認証のリクエスト
curl -H "Authorization: Token abc123your_token_here" http://localhost:8000/api/articles/
DRFには以下のパーミッションクラスが組み込まれています。
| パーミッション | 説明 |
|---|---|
AllowAny | 誰でもアクセス可能(認証不要) |
IsAuthenticated | 認証済みユーザーのみ |
IsAdminUser | 管理者ユーザーのみ |
IsAuthenticatedOrReadOnly | 認証済みは全操作可、未認証は読み取りのみ |
from rest_framework import viewsets, permissions
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.action in ['list', 'retrieve']:
# 一覧・詳細は誰でもアクセス可能
return [permissions.AllowAny()]
# 作成・更新・削除は認証必須
return [permissions.IsAuthenticated()]
プロジェクト固有の権限が必要な場合は、カスタムパーミッションを作成します。
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
"""
記事の作成者のみ編集・削除可能。
それ以外のユーザーは読み取りのみ。
"""
def has_object_permission(self, request, view, obj):
# GET, HEAD, OPTIONS は全員許可
if request.method in permissions.SAFE_METHODS:
return True
# 書き込み系は作成者のみ
return obj.author == request.user
from .permissions import IsAuthorOrReadOnly
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly]
def perform_create(self, serializer):
# 作成時に自動でauthorを設定
serializer.save(author=self.request.user)
REST API構築チェックリスト
- REST APIの基本概念(リソース + HTTPメソッド)を理解した
- JsonResponseでシンプルなAPIを作れるようになった
- Django REST Frameworkをインストール・設定できた
- ModelSerializerでモデルのシリアライズ・バリデーションができた
- ModelViewSet + Routerで最小コードのCRUD APIを構築できた
- 認証(Token認証)とパーミッションの設定ができた