개발공부

boto3로 S3 파일 업로드 본문

Python/Flask

boto3로 S3 파일 업로드

mscha 2022. 6. 24. 12:11

 

https://mscha.tistory.com/186?category=1081837 

 

S3 버킷 생성

aws 사이트로가서 로그인 후 S3 에 들어간다. 버킷 만들기를 누른다. 버킷명을 입력한다. ACL 활성화를 하면 다른 사용자가 접근할 수 있다. 퍼블릭액세스 차단을 풀면 다른 사용자가 접근 할 수 있

mscha.tistory.com

app.py

from flask import Flask
from flask_jwt_extended import JWTManager
from flask_restful import Api

from config import Config
from resources.image import FileUploadResource
from resources.posting import PostingResource




app = Flask(__name__)

# 환경변수 셋팅
app.config.from_object(Config)

# JWT 토큰 라이브러리만들기
jwt = JWTManager(app)



api = Api(app)

api.add_resource(FileUploadResource, '/upload')
api.add_resource(PostingResource, '/posting')

if __name__ == '__main__' :
    app.run()

mysql_connection.py

import mysql.connector

def get_connection() :
    connection = mysql.connector.connect(
        host = '호스트명',
        database = 'DB명',
        user = '유저명',
        password = '패스워드',
    )
    return connection

config.py

class Config :
    JWT_SECRET_KEY = 'secret key'
    JWT_ACCESS_TOKEN_EXPIRES = False
    PROPAGATE_EXCEPTIONS = True

    
    # AWS 사용자명
    ACCESS_KEY = '본인 IAM accesskey'
    SECRET_ACCESS = '본인 IAM secret access'

    # S3 버킷이름과, 기본 URL 주소 셋팅
    S3_BUCKET = 's3 버킷명'
    S3_LOCATION ='s3 버킷 URL'

 

resources/upload.py

from datetime import datetime
from flask_restful import Resource
from flask import request
from flask_jwt_extended import get_jwt_identity, jwt_required
from importlib_metadata import files
import boto3
from config import Config
class FileUploadResource(Resource) :
    # 이미지 S3에 업로드
    def post(self) :

        # 1. 클라이언트로부터 데이터를 받아온다.
        # request.files 에 파일을 받아온다.
        # 따라서 파일이 없는 상태로 API가 호출되면
        # 에러 메세지를 클라이언트에 응답해주자.
        
        # photo란, 클라이언트에서 보내는 key
        if 'photo' not in request.files :
            return {'error' : '파일을 업로드 하세요.'}, 400

        # 클라이언트로부터 파일을 받아온다.
        file = request.files['photo']

        # 파일명을 우리가 변경해 준다.
        # 파일명은, 유니크하게 만들어야 한다.
        current_time = datetime.now()
        new_file_name = current_time.isoformat().replace(':', '_') + ('.jpg')

        # 유저가 올린 파일의 이름을 내가 만든 파일명으로 변경
        file.filename = new_file_name

        # S3에 업로드 하면 된다.
        # AWS의 라이브러리를 사용해야 한다.
        # 이 파이썬 라이브러리가 boto3 라이브러리다.
        # pip install boto3
        s3 = boto3.client('s3', 
                    aws_access_key_id = Config.ACCESS_KEY,
                    aws_secret_access_key = Config.SECRET_ACCESS)

        try :
            s3.upload_fileobj(file,             # 업로드 파일
                            Config.S3_BUCKET,   # 버킷 url
                            file.filename,      # 파일명
                            ExtraArgs = {'ACL' : 'public-read', 'ContentType' : file.content_type})    # 권한, 타입

        except Exception as e:
            return {'error' : str(e)}, 500

        return {'result' : 'success',
                'imgUrl' : Config.S3_LOCATION + file.filename}

 

resources/posting.py

from datetime import datetime
from flask_restful import Resource
from flask import request
from config import Config
from mysql_connection import get_connection
import mysql.connector
from flask_jwt_extended import get_jwt_identity, jwt_required
import boto3
class PostingResource(Resource) :
    # 이미지를 S3에 업로드하고, 데이터베이스에는 이미지 url과 content 저장 
    def post(self) :

        # 1. 클라이언트로부터 데이터를 받아온다.
        # photo(file), content(text)

        if 'photo' not in request.files:
            return {'error' : '파일을 업로드하세요'}, 400
        file = request.files['photo']
        content = request.form['content']

        # 2. S3에 파일 업로드
        # 클라이언트로부터 파일을 받아온다.
        
        file = request.files['photo']

        # 파일명을 우리가 변경해 준다.
        # 파일명은, 유니크하게 만들어야 한다.
        current_time = datetime.now()
        new_file_name = current_time.isoformat().replace(':', '_') + ('.jpg')

        # 유저가 올린 파일의 이름을 내가 만든 파일명으로 변경
        file.filename = new_file_name

        # S3에 업로드 하면 된다.
        # AWS의 라이브러리를 사용해야 한다.
        # 이 파이썬 라이브러리가 boto3 라이브러리다.
        # pip install boto3
        s3 = boto3.client('s3', 
                    aws_access_key_id = Config.ACCESS_KEY,
                    aws_secret_access_key = Config.SECRET_ACCESS)

        try :
            s3.upload_fileobj(file,             # 업로드 파일
                            Config.S3_BUCKET,   # 버킷 url
                            file.filename,      # 파일명
                            ExtraArgs = {'ACL' : 'public-read', 'ContentType' : file.content_type})    # 권한, 타입

        except Exception as e:
            return {'error' : str(e)}, 500

        # 3. DB에 저장
        try :
            # 데이터 insert
            # 1. DB에 연결
            connection = get_connection()
            
            # 2. 쿼리문 만들기
            query = '''insert into posting
                    (content, imgUrl)
                    values
                    (%s, %s);'''
                    
            # recode 는 튜플 형태로 만든다.
            recode = (content, file.filename)

            # 3. 커서를 가져온다.
            cursor = connection.cursor()

            # 4. 쿼리문을 커서를 이용해서 실행한다.
            cursor.execute(query, recode)

            # 5. 커넥션을 커밋해줘야 한다 => 디비에 영구적으로 반영하라는 뜻
            connection.commit()

            # 6. 자원 해제
            cursor.close()
            connection.close()

        except mysql.connector.Error as e :
            print(e)
            cursor.close()
            connection.close()
            return {"error" : str(e)}, 503

        return {'result' : 'success'}

 

1. 사진 업로드하는 API

2. 사진 url, content를 DB에 저장하는 API

select * from posting;