Django REST FrameworkのViewSetにカスタム操作を追加する@actionデコレータの実践

コレクションレベルのカスタムエンドポイント実装

detail=Falseを指定することで、モデル全件を対象とするエンドポイントを構築できます。アクティブユーザー数の集計処理を例に説明します。

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet

class AccountViewSet(ModelViewSet):
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

    @action(detail=False, methods=['get'])
    def active_summary(self, request):
        active_count = Account.objects.filter(status='active').count()
        return Response({'active_accounts': active_count})

個別レコード操作の実装パターン

detail=Trueを設定すると、特定のリソースインスタンスに対する操作を定義可能です。アカウント一時停止機能の実装例を示します。

class AccountViewSet(ModelViewSet):
    # ...省略...
    
    @action(detail=True, methods=['patch'])
    def suspend(self, request, pk=None):
        target = self.get_object()
        target.status = 'suspended'
        target.save(update_fields=['status'])
        return Response({'result': 'suspension completed'})

マルチメソッドエンドポイントの構築

複数のHTTPメソッドを同一エンドポイントで処理する実装方法です。データ検証と登録を統合したエンドポイント例:

class DataViewSet(ModelViewSet):
    # ...省略...
    
    @action(detail=False, methods=['get', 'put'])
    def process_data(self, request):
        if request.method == 'GET':
            return Response({'instruction': 'send_data_via_PUT'})
        if request.method == 'PUT':
            validation_result = validate_data(request.data)
            return Response({'validation': validation_result})

カスタムURLパスの設定テクニック

url_pathとurl_nameパラメータでエンドポイントのURIを最適化します。パスワード再設定機能の実装:

class AuthViewSet(ModelViewSet):
    # ...省略...
    
    @action(
        detail=True,
        methods=['post'],
        url_path='reset-password',
        url_name='password_reset'
    )
    def password_renewal(self, request, pk=None):
        account = self.get_object()
        new_hash = generate_password_hash(request.data['new_password'])
        account.set_password(new_hash)
        return Response({'status': 'password_updated'})

権限制御の組み込み方法

permission_classesパラメータでカスタムアクションにアクセス制御を適用します。管理者専用の分析データ提供例:

from rest_framework.permissions import IsAdminUser

class AnalyticsViewSet(ModelViewSet):
    # ...省略...
    
    @action(
        detail=False,
        methods=['get'],
        permission_classes=[IsAdminUser]
    )
    def system_metrics(self, request):
        metrics = collect_system_data()
        return Response(metrics)

バイナリデータ対応の応用例

FileResponseを活用したレポートファイルの配信実装。MIMEタイプとヘッダの設定に注目:

class ReportViewSet(ModelViewSet):
    queryset = ReportDocument.objects.all()
    serializer_class = ReportSerializer

    @action(detail=True, methods=['get'])
    def export(self, request, pk=None):
        report = self.get_object()
        stream = report.generate_pdf_stream()
        response = HttpResponse(stream, content_type='application/vnd.pdf')
        response['Content-Disposition'] = f'attachment; filename="report_{report.id}.pdf"'
        return response

タグ: Django REST Framework ViewSet Custom Actions

6月30日 20:35 投稿