1
0

[Django REST Framework] Lambdaで定期的に実行するバッチ削除処理APIの作成方法を見てみよう!

Last updated at Posted at 2024-03-22

概要

Lambdaで定期的に実行するバッチ削除処理APIの作成方法

目的

掲題の方法を説明する

使用技術

application/pyproject.toml
python = "^3.11.2"
Django = "^4.2.7"
djangorestframework = "^3.14.0"
pytest = "^7.4.3"
pytest-django = "^4.7.0"

早速コードを見ていきましょう!

今回の削除する対象はSMS送信履歴とします

application/project/serializers.py
from rest_framework import serializers

class DeleteSmsSendHistorySerializer(serializers.Serializer):
    """SMS送信履歴削除用のシリアライザ"""

    token = serializers.CharField(max_length=64)

application/project/views/sms.py
from datetime import timedelta

from django.db import DatabaseError, transaction
from django.utils import timezone
from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

# マジックナンバーを防ぐため、定数化しています
from common.constant import (
    DELETE_THRESHOLD_DAYS,
    DELETED_RECORDS_COUNT_INDEX,
    DELETED_SMS_SEND_HISTORY_RECORDS_INDEX,
)
# settingsはpydanticを使用して環境変数情報を持っています
from common.environment_variable import settings
from project.models import SmsSendHistory
from project.serializers import DeleteSmsSendHistorySerializer


class SmsSendHistoryViewSet(viewsets.GenericViewSet):
    """SMS送信履歴削除用のAPI"""

    serializer_class = DeleteSmsSendHistorySerializer

    @action(methods=["post"], detail=False)
    def delete_old_record(self, request):
        """Lambdaで使用するSMS送信履歴削除API
        180日以前の古いSMS送信履歴を削除する

        Parameters:
            token(str): Lambda実行用のトークン

        Returns:
            detail (str): メッセージ
        """
        serializer = self.get_serializer_class()(data=request.data)
        serializer.is_valid(raise_exception=True)
        if serializer.validated_data.get("token") != settings.LAMBDA_TOKEN:
            return Response(
                {"detail": "無効なトークンです"},
                status.HTTP_400_BAD_REQUEST,
            )

        delete_date = timezone.localtime() - timedelta(
            days=DELETE_THRESHOLD_DAYS
        )
        try:
            with transaction.atomic():
                deleted_records_info = SmsSendHistory.objects.filter(
                    created_at__lte=delete_date
                ).delete()
        except DatabaseError:
            return Response(
                {"detail": "SMS送信履歴の削除に失敗しました"},
                status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        deleted_count = 0
        if deleted_records_info[DELETED_RECORDS_COUNT_INDEX] != 0:
            deleted_count = deleted_records_info[
                DELETED_SMS_SEND_HISTORY_RECORDS_INDEX
            ]["project.SmsSendHistory"]

        return Response(
            {"detail": f"180日前のSMS送信履歴を{deleted_count}件削除しました"},
            status.HTTP_200_OK,
        )

重要なポイントを解説していきましょう!

期待しているLambdaからのリクエストかどうかをチェックしています

if serializer.validated_data.get("token") != settings.LAMBDA_TOKEN:
       return Response(
           {"detail": "無効なトークンです"},
           status.HTTP_400_BAD_REQUEST,
       )

現在の時間から指定した過去の日付を取得します(今回は180日前)

delete_date = timezone.localtime() - timedelta(
            days=DELETE_THRESHOLD_DAYS
        )
# 結果例
delete_date: 2023-09-24 15:52:39.155157+09:00
type(delete_date): <class 'datetime.datetime'>

objectsマネージャーを使用し、180日以前のSMS送信履歴を削除します
トランザクション処理に失敗した場合は500エラーを返すようにしています

try:
    with transaction.atomic():
        deleted_records_info = SmsSendHistory.objects.filter(
            created_at__lte=delete_date
        ).delete()
except DatabaseError:
    return Response(
        {"detail": "SMS送信履歴の削除に失敗しました"},
        status.HTTP_500_INTERNAL_SERVER_ERROR,
    )

定数化している数字を変更するだけで、要件に沿ったバッチ削除処理APIが開発できます!ご参考までに🐰

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0