일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- bcrypt
- OSI7계층
- wecode
- nodeJS
- JWT
- 실행 컨텍스트
- node
- typescript
- docker
- 자바스크립트
- 호이스팅
- Django
- async/await
- 프로미스
- 스코프
- westagram
- javascript
- rebase
- 장고초기세팅
- django westagram
- 노드
- manytomanyfield
- status code
- Jest
- 트랜잭션
- on_delete
- crud2
- pm2
- CORS
- TypeError: this.boardRepository.createBoard is not a function
- Today
- Total
될때까지
((WnB)) 호스트 집 이미지 등록 AWS S3, boto3 사용하여 구현하기 본문
호스트가 집을 등록하려면 집 이미지도 첨부하게 된다. 첨부한 이미지 파일들은 어디에 저장해야할까?
WnB 프로젝트에서는 AWS S3를 사용해서 저장했다. S3가 무엇이고 왜 사용하는지 간단하게 알아보자.
S3란?
Simple Storage Service의 약자로 인터넷용 스토리지 서비스를 말한다.
이미지 파일들을 저장할 수 있는 공간으로 버킷(bucket)이라는 최상위 디렉토리에 저장된다.
S3의 버킷은 무한대의 객체(저장되는 데이터 단위를 일컫음)를 저장할 수 있기 때문에 확장 및 축소에 신경을 쓰지 않아도 되서 관리에 용이하다는 장점이 있다.
난 기존에 만들었던 버킷을 사용할것이기 때문에, 버킷 생성 관련 자료는 >>해당 유튜브 참고 <<
boto3
boto3는 AWS에서 제공하는 파이썬 용 SDK(software development kit)다. boto3를 이용하면 S3를 사용할 수 있다.
boto3 설치하기
poetry add boto3
boto3를 사용할 때 client, resource, session 3가지 방식이 있는데 이 중 client와 resource가 가장 많이 사용된다고 한다.
resource는 객체지향적 인터페이스로 자원에 대해 조금 더 직관적이다. 따라서 resource로 작성된 코드가 더 단순하고 읽기 쉽다.
하지만 모든 리소스에 대해 사용할 수 없으므로 그럴때는 client를 사용해야한다. 자세한 내용은 잘 정리해둔 블로그 참고 >>클릭<<
먼저 my_settings.py에 아래 정보들을 적어준다.
(IAM 생성 시 다운로드 받았던 .csv파일에 있음)
# my_settings.py
AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID' # AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY = 'AWS_SECRET_ACCESS_KEY' # AWS_SECRET_ACCESS_KEY
AWS_BUCKET_NAME = 'AWS_BUCKET_NAME' # 생성한 버킷 이름
AWS_REGION = 'ap-northeast-2'
그다음 이미지 업로드 코드를 작성할 views.py에서 설치한 boto3를 불러온다.
그리고 아래와 같이 코드를 작성하면 된다.
import boto3
# hosts > views.py
import boto3
class RegisterRoomView(View):
@signin_decorator
def post(self, request):
data = request.POST
...생략...
s3 = boto3.resource('s3',
AWS_ACCESS_KEY_ID = AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY = AWS_SECRET_ACCESS_KEY)
s3.Bucket(AWS_BUCKET_NAME).put_object(Key = '파일이름', body=파일, ContentType = '파일타입')
Bucket()을 이용하여 AWS S3에 만든 버킷(괄호안에 버킷 이름)에 접근할 수 있고,
put_object를 사용함으로써 파일을 업로드할 수 있다.
그럼 여기서 body에 담을 실제 파일을 가져오자.
파일을 전달받으려면 request에 있는 FILES메소드를 사용하고 1개가 아닌 여러개의 파일이 올라오니까 getlist를 사용하면 된다.
# hosts > views.py
import boto3
class RegisterRoomView(View):
@signin_decorator
def post(self, request):
data = request.POST
try:
files = request.FILES.getlist('files') # <- 이 코드 추가
...생략...
s3 = boto3.resource('s3',
AWS_ACCESS_KEY_ID = AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY = AWS_SECRET_ACCESS_KEY)
s3.Bucket(AWS_BUCKET_NAME).put_object(Key = '파일이름', body=파일, ContentType = '파일타입')
여기서 버킷에 폴더를 만들고 파일들을 정리하면 더 깔끔할 것 같다. 저장될 파일의 이름을 지정해주자
# hosts > views.py
... 생략...
# 집 이미지 등록하기
for file in files: # 여러개의 파일들이 있기 때문에 반복문을 돌면서 1개씩 s3에 저장해야함
s3 = boto3.resource('s3',
aws_access_key_id = AWS_ACCESS_KEY_ID,
aws_secret_access_key = AWS_SECRET_ACCESS_KEY)
# S3에 object저장하기
s3.Bucket(AWS_BUCKET_NAME).put_object(Key = str(host.id) + f'/{file}', # 호스트 id별로 폴더를 생성해서 관리
Body = file,
ContentType = 'jpg')
# DB에 저장하면 끝
Image.objects.create( # Image에는 url과 room이 있음
url = IMAGE_URL + f'/{host.id}/{file}', # 저장할 url 경로 형식 지정
room_id = room.id
)
이대로 코드를 작성하고 포스트맨으로 테스트를 했다.
포스트맨으로 file을 올리는 방법은 text를 file로 바꿔주면 된다.
올리고 AWS S3 Bucket을 확인해보자.
호스트의 id인 5번 폴더가 생성됐고 그 안에 사진파일이 잘 저장된 걸 확인할 수 있다.
다운로드 받았던 파일의 이름 그대로 올려줬는데 파일이름이 중복될 수도 있으니
해당 부분을 uuid를 사용하여 중복없이 올라가도록 수정해주자.
# 집 이미지 등록하기
for file in files:
file._set_name(str(uuid.uuid4())) # <- 해당 코드를 추가하면 된다.
s3 = boto3.resource('s3',
aws_access_key_id = AWS_ACCESS_KEY_ID,
aws_secret_access_key = AWS_SECRET_ACCESS_KEY)
# S3에 object저장하기
s3.Bucket(AWS_BUCKET_NAME).put_object(Key = str(host.id) + f'/{file}',
Body = file,
ContentType = 'jpg')
# S3에 저장된 경로는 "https://AWS_BUCKET_NAME.s3.AWS_REGION.amazonaws.com/+파일이름"이다.
# 해당 경로를 사용해 DB에 저장하기
Image.objects.create(
url = IMAGE_URL + f'/{host.id}/{file}',
room_id = room.id
)
그래서 완성된 코드는 아래와 같다!.
class RegisterRoomView(View):
@signin_decorator
def post(self, request):
data = request.POST
try:
host = Host.objects.get(user=request.user)
name = data['room_name']
address = data['state/province/region']
detail_address = data['detail_address']
price = data['price']
description = data['description']
latitude = data['latitude']
longitude = data['longitude']
maximum_occupancy = data['maximum_occupancy']
bedroom = data['bedroom']
bathroom = data['bathroom']
bed = data['bed']
category = data['category_id']
room_type = data['room_type_id']
facility_ids = data.getlist('facility_ids') # 리스트로 담김 ['1', '2', '4']
files = request.FILES.getlist('files') # 이미지 첨부
...생략...
with transaction.atomic():
room, is_created = Room.objects.get_or_create(
name = name,
defaults = {
"address" : address,
"detail_address" : detail_address,
"price" : price,
"description" : description,
"latitude" : latitude,
"longitude" : longitude,
"maximum_occupancy" : maximum_occupancy,
"bedroom" : bedroom,
"bathroom" : bathroom,
"bed" : bed,
"host" : host,
"category" : Category.objects.get(id=category),
"room_type" : RoomType.objects.get(id=room_type)
}
)
...생략...
# 집 이미지 등록하기
for file in files: # 여러개의 파일들을 반복을 돌면서 1개씩 올려야함
file._set_name(str(uuid.uuid4()))
s3 = boto3.resource('s3',
aws_access_key_id = AWS_ACCESS_KEY_ID,
aws_secret_access_key = AWS_SECRET_ACCESS_KEY)
# S3에 object저장하기
s3.Bucket(AWS_BUCKET_NAME).put_object(Key = str(host.id) + f'/{file}', # 호스트 id별로 폴더 생성해서 관리
Body = file,
ContentType = 'jpg')
# DB에 저장하면 끝
Image.objects.create( # Image에는 url과 room이 있음
url = IMAGE_URL + f'/{host.id}/{file}', # 저장할 url 경로 형식 지정
room_id = room.id
)
# 저장된 이미지 파일들 가져와서 내보내주기
images = Image.objects.filter(room_id = room.id).all()
room_info = {
"id" : room.id,
"room_name" : room.name,
"address" : room.address + room.detail_address,
"price" : room.price,
"bedroom" : room.bedroom,
"bathroom" : room.bathroom,
"bed" : room.bed,
"host_name" : room.host.user.last_name + room.host.user.first_name,
"category" : room.category.name,
"room_type" : room.room_type.name,
"facilities": [room_facility.room_facility.name for room_facility in RoomFacility.objects.filter(room = room.id).all()],
"images" : [image.url for image in images]
}
return JsonResponse({'message':'SUCCESS', 'data':{'room_info':room_info}}, status=201)
except Host.DoesNotExist:
return JsonResponse({'message':'ONLY_HOST_CAN_REGISTER_HOUSE'}, status=403)
except KeyError:
return JsonResponse({'message':'KEY_ERROR'}, status=400)
s3버킷에 저장된 파일을 눌러도 이미지가 잘 보이고, DB에 저장된 경로를 url에 입력해도 사진이 제대로 보인다면 성공이다!
'프로젝트 > wecode2차 : WnB' 카테고리의 다른 글
((WnB)) 호스트 집 인포만 등록하기 (0) | 2022.10.20 |
---|---|
((WnB)) 일반 회원가입, 로그인, 호스트 등록하기 기능 구현 (0) | 2022.10.20 |
((WnB)) Poetry 적용하기 (0) | 2022.10.20 |
((WnB)) 팀 프로젝트 이후 개인 깃허브로 옮겨서 작업하기 (0) | 2022.10.20 |
((WnB)) 위코드 2차 프로젝트 회고록 (0) | 2022.08.13 |