[AWS] Boto3 - AWS S3 Upload, Download, Delete 구현

Jayson Hwang·2022년 6월 12일
1

AWS

목록 보기
2/2
post-thumbnail

AWS S3??

아마존에서 제공하는 서비스로 클라우드 스토리지

1.. AWS 가입 및 S3 버킷, CORS 설정

아마존 공식 문서 링크

아마존 공식 문서를 보고 가입을 진행하면 된다.
IAM 사용자가 아닌, 루트 사용자로 진행해도 무방하다.(오히려 루트 사용자가 더 편할수도)

버킷 생성

  • 버킷 생성 관련 영상 링크
  • S3 권한 탭에서 아래와 같이 버킷 정책을 알맞게 설정해주어야함
    설정 과정에 있어서 변경이 안되는 경우가 있음. 그 이유는 퍼블릭 액세스 차단을 해두었기 때문!! 따라서 엑세스 차단을 풀어주면 버킷 정책 변경이 가능하다.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject"
            ],
            "Resource": "(버킷 명)/*"
        }
    ]
}
  • 추가로 CORS(Cross-origin) 또한 설정해주어야한다
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ],
        "MaxAgeSeconds": 3000
    }
]

2.. Upload

BOTO3 공식문서

공식 문서를 확인하면서 본인이 사용하고자하는 method를 찾아보는 것이 중요!!!

첫번째로는 boto3를 설치해야한다.
$ pip install boto3

이하 Upload 관련 작성 코드 ::

class ResumeUploadView(View):
    
    s3_client = boto3.client(
        's3', 
        aws_access_key_id     = settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key = settings.AWS_SECRET_ACCESS_KEY
    )

    @signin_decorator
    def post(self, request):
        user = request.user

        # 요청에 파일이 제대로 담겨왔는지 검사
        if request.FILES.__len__() == 0:
            return JsonResponse({"message" : "NO_FILES_TO_UPLOAD"}, status=400)

        file = request.FILES['resume']
        # 만약 여러개의 파일을 받아 올리게 된다면 아래 코드 사용...
        # file = request.FILES.getlist('resumes')

        # 업로드되는 파일의 형식이 PDF가 아니라면 작업을 멈추고 에러 메세지 출력
        if file.name.endswith('.pdf') == False:        
            return JsonResponse({"message" : "CAN_ONLY_UPLOAD_PDF"}, status=400)

        file_name = uuid.uuid4().hex[:12]

        self.s3_client.upload_fileobj(
            file, 
            settings.AWS_STORAGE_BUCKET_NAME, 
            file_name, 
            ExtraArgs = {"ContentType": file.content_type}
        ) 

        Resume(
            name     = file.name,
            file_url = f"https://{settings.AWS_S3_CUSTOM_DOMAIN}/{file_name}",
            user_id  = user
        ).save()

        return JsonResponse({"message" : "UPLOAD_SUCCESS"}, status=201)
  • request.FILES.__len__() 를 통해서 파일 요청에 제대로 담겼는지 확인
  • file.name.endswith('.pdf')를 통해서 pdf 파일만 업로드 되도록 구성
  • uuid.uuid4().hex[:12]를 통해서 업로드되는 파일의 이름을 랜덤str 변환
  • client.upload_fileobj() 사용...
    관련해서는 BOTO3 공식문서를 참고하면 된다.

3.. Delete(S3 스토리지에 저장된 파일 삭제)

Delete 관련된 코드 ::

    @signin_decorator
    def delete(self, request, resume_id):
        try:
            user = request.user
            resume    = Resume.objects.get(id = resume_id)
            file_url  = resume.file_url
            file_name = file_url[54:]

            if resume.user.id !=user:
                return JsonResponse({"message" : "UNAUTHORIZED_USER"}, status=401)

            urllib.request.urlopen(file_url).getcode()
            self.s3_client.delete_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=file_name)
            resume.delete()

            return JsonResponse({"message" : "DELETE_SUCCESS"}, status=200)

        except Resume.DoesNotExist:
            return JsonResponse({"message" : "RESUME_DOES_NOT_EXIST"}, status=404)

4.. Download(S3에 저장된 파일 로컬에 다운로드)

Download 관련 코드 ::

class ResumeDownloadView(View):
    
    s3_client = boto3.client(
        's3', 
        aws_access_key_id     = settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key = settings.AWS_SECRET_ACCESS_KEY
    )
    # @signin_decorator
    def get(self, request, resume_id):
        try:
            # 데코레이터 사용 가능해지면 그때 사용할 것
            # user = request.user
            user      = User.objects.get(id=17).id
            resume    = Resume.objects.get(id=resume_id)
            file_name = resume.file_url[54:]

            if resume.user.id != user:
                return JsonResponse({"message" : "UNAUTHORIZED_USER"}, status=401)

            self.s3_client.download_file(
                settings.AWS_STORAGE_BUCKET_NAME,
                file_name,
                str(Path.home() / "Downloads/resume.pdf"),
            )

            return JsonResponse({"message" : "DOWNLOAD_SUCCESS"}, status=200)

        except Resume.DoesNotExist:
            return JsonResponse({"message" : "RESUME_DOES_NOT_EXIST"}, status=404)
  • client.download_file()를 통해서 S3에 저장된 파일 다운로드
  • str(Path.home() / "Downloads/resume.pdf"
    다운로드하고 로컬에 저장될 때, Downloads 폴더에 resume.pdf 라는 파일명으로 저장될 수 있도록 지정하기 위해 작성한 코드
    (더 나아가서는 다운로드되는 파일명을 업로드하는 파일명과 동일하게 구현하고 싶었으나 아직은 지식이 부족하여 구현을 못함...차후에 구현하도록 하겠음...)
profile
"Your goals, Minus your doubts, Equal your reality"

0개의 댓글