Django에서 S3에 파일 업로드

2021. 12. 5. 14:29프로그래밍/인프라

반응형

Django에서 boto3를 사용하여 S3와 연결 및 파일 업로드

준비사항

  • AWS IAM user 셋업
  • AWS S3 bucket 셋업

 

1. boto3 라이브러리 설치

  • boto3는 파이썬용 AWS라이브러리이다.
pip install boto3

 

2. 코드 작성

2-1. 엔드포인트

우선 호출하는 부분에서 어떻게 호출할 것인지를 작성해본다.

  • 장고에서는 전송된 파일이 request.FILES를 통해 전달된다.
  • FileUpload라는 wrapper class를 통해 S3 클라이언트를 생성하고 ,파일업로드 기능을 수행하는 함수를 호출하여 profile_image_url 값을 리턴받는다.
from storages import FileUpload, s3_client

class ProfileUploadView(View):
    def post(self, request):
        # ...

        file              = request.FILES['filename']
        profile_image_url = FileUpload(s3_client).upload(file)

        # ...

 

2-2. storages.py

storages.py에서는 FileUpload, MyS3Client 클래스와 MyS3Client 클래스로 s3_client 인스턴스를 생성해줄 것이다.

FileUpload 클래스

  • 어떤 Service client를 받더라도 엔드포인트에서는 FileUpload클래스의 인스턴스를 받아서 사용하면 된다.
  • 이런 class를 wrapper class라고 하며, 파일업로드를 구현하는 개발자는 storages.py안의 FileUpload클래스와 service client만 알고 있으면 된다.
class FileUpload:
    def __init__(self, client):
        self.client = client

    def upload(self, file):
        return self.client.upload(file)
  • FileUpload 클래스를 초기화할 때 인자로 service client를 받는다.
  • s3_client = FileUpload(s3_client)
  • upload() 메서드를 호출하면 client.upload() 메서드를 호출한다.
  • s3_client = FileUpload(s3_client).upload(File)

 

MyS3Client 클래스

  • S3 클라이언트를 생성해서 연결하고, 파일을 업로드 하는 부분
  • uuid 를 사용해서 파일이름이 중복되어 덮어씌워지는 것을 방지하였다.
  • MyS3Client의 인스턴스(s3_client)를 생성해놓고 사용할 수 있도록 하였다.
import boto3
import uuid

from config.settings import AWS_ACCESS_KEY, AWS_SECRET_KEY, S3_BUCKET_NAME

class MyS3Client:
    def __init__(self, access_key, secret_key, bucket_name):
        boto3_s3 = boto3.client(
            's3',
            aws_access_key_id     = access_key,
            aws_secret_access_key = secret_key
        )
        self.s3_client   = boto3_s3
        self.bucket_name = bucket_name

    def upload(self, file):
        try: 
            file_id    = str(uuid.uuid4())
            extra_args = { 'ContentType' : file.content_type }

            self.s3_client.upload_fileobj(
                    file,
                    self.bucket_name,
                    file_id,
                    ExtraArgs = extra_args
                )
            return f'https://{self.bucket_name}.s3.ap-northeast-2.amazonaws.com/{file_id}'
        except:
            return None


# MyS3Client instance
s3_client = MyS3Client(AWS_ACCESS_KEY, AWS_SECRET_KEY, S3_BUCKET_NAME)

 

마치며...

S3를 처음 사용해보면서 이미지를 클라우드에 저장해놓고 거기서 생성된 Url을 Database에 저장한다는 개념이 낯설었는데 직접 해보니깐 개념이 잡히는 것 같았다.

또 파일업로드 하는 부분을 클래스화하면서 완벽하진 않겠지만, 좀 더 구조적으로 깔끔하게 작성한 것 같아서 만족스럽다. 😀️

반응형

'프로그래밍 > 인프라' 카테고리의 다른 글

Amazon Virtual Private Cloud (VPC)  (0) 2021.11.24
AWS  (0) 2021.11.17