DRF における 9 つのビューサブクラスの活用
Django REST Framework (DRF) では、GenericAPIView と各種 Mixin を組み合わせることで、特定の機能に特化したビューサブクラスが提供されています。これにより、最小限のコードで CRUD 機能を実装できます。
CreateAPIView: 作成のみListAPIView: 一覧取得のみRetrieveAPIView: 単一取得のみDestroyAPIView: 削除のみUpdateAPIView: 更新のみListCreateAPIView: 一覧取得と作成RetrieveUpdateAPIView: 単一取得と更新RetrieveDestroyAPIView: 単一取得と削除RetrieveUpdateDestroyAPIView: 単一取得、更新、削除
ViewSet によるビューの集約
ModelViewSet を継承することで、上記 5 つの主要な API 機能を 1 つのクラスにまとめることができます。これにより、ルーティングの記述方法が as_view({'get': 'list', 'post': 'create'}) のように、HTTP メソッドとアクションの対応を指定する形式に変わります。
# views.py
from rest_framework.viewsets import ModelViewSet
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# urls.py
from django.urls import path
from .views import ArticleViewSet
urlpatterns = [
path('articles/', ArticleViewSet.as_view({'get': 'list', 'post': 'create'})),
path('articles/<int:pk>/', ArticleViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
})),
]
ViewSetMixin の仕組み
ModelViewSet がルーティングの形式を変更できるのは、ViewSetMixin を継承しているためです。このクラスは as_view メソッドをオーバーライドしており、引数として受け取ったマッピング(辞書)を基に、リクエストメソッドに応じた適切なハンドラを動的に割り当てます。
この仕組みにより、開発者はメソッド名を自由に定義し、ルーティング側でそれを指定することが可能になります。
DRF ルーティングシステムと自動生成
ViewSet を使用する場合、SimpleRouter や DefaultRouter を利用してルーティングを自動生成するのが一般的です。
from rest_framework.routers import SimpleRouter
from .views import ArticleViewSet
# ルーターのインスタンス化
router = SimpleRouter()
# ビューセットの登録
router.register('articles', ArticleViewSet, basename='article')
# URLパターンの統合
urlpatterns = [
# 他のパス...
]
urlpatterns += router.urls
@action デコレータによるカスタムアクション
標準の CRUD 以外のアクション(例:公開処理、パスワード変更など)を追加する場合、@action デコレータを使用します。
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@action(methods=['post'], detail=True, url_path='publish-content')
def set_published(self, request, pk=None):
article = self.get_object()
article.status = 'published'
article.save()
return Response({'status': '記事を公開しました'}, status=status.HTTP_200_OK)
detail=True を指定すると、/articles/{pk}/publish-content/ のような ID を含む URL が生成されます。detail=False の場合は /articles/publish-content/ のようなコレクション単位の URL になります。
認証コンポーネントの基礎実装
API のセキュリティを確保するために、ユーザー認証は不可欠です。以下は、UUID を使用した簡易的なトークン認証のロジック例です。
# models.py
from django.db import models
class SiteUser(models.Model):
name = models.CharField(max_length=50)
secret_key = models.CharField(max_length=50)
class AccessToken(models.Model):
token_str = models.CharField(max_length=100)
owner = models.OneToOneField(to='SiteUser', on_delete=models.CASCADE)
# views.py
import uuid
from rest_framework.viewsets import ViewSet
from .models import SiteUser, AccessToken
class AuthViewSet(ViewSet):
@action(methods=['POST'], detail=False)
def authenticate(self, request):
user_name = request.data.get('username')
pwd = request.data.get('password')
target_user = SiteUser.objects.filter(name=user_name, secret_key=pwd).first()
if target_user:
new_token = str(uuid.uuid4())
AccessToken.objects.update_or_create(
owner=target_user,
defaults={'token_str': new_token}
)
return Response({'token': new_token, 'msg': 'Success'})
return Response({'msg': 'Authentication failed'}, status=status.HTTP_401_UNAUTHORIZED)
認証に成功すると、一意のトークンが発行され、以降のリクエストではこのトークンをヘッダー等に含めることで、ログイン状態を証明します。