이전의 포스팅에선 로그인과 회원가입 부분까지 구현을 했었는데, 처음 해보는 부분이기도 했고 백엔드까지 직접 처리를 해줘야 하다보니 고생을 좀 많이 했었던 것 같다.
하지만 그 부분을 해결하고 나서는 기획했던 대로 쭉쭉 컴포넌트들과 기능을 만들었다.
100% 완성은 아니고, 90%는 만든 것 같다.
우선 게시글 썸네일과 프로필 사진 업데이트 부분을 구현하기 위해선 이미지 서버가 필요했다. 내가 직접 백엔드 부분을 구현해야 하다보니 참 골치가 아파졌다..
이미지 서버는 이미 기획 단계에서 AWS의 S3를 사용하려고 했었다.
일단은 AWS 안의 S3 페이지로 가서 버킷 만들기를 통해 만들어 줄 수 있었다. 이 부분은 크게 어렵지 않다. 검색만 해도 너무 많은 자료가 있어서 버킷은 그 곳들을 참고하길 바란다!
{
"Version": "2012-10-17",
"Id": "Policy1680030209370",
"Statement": [
{
"Sid": "Stmt1680030202034",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::cardlog-bucket/*"
}
]
}
내가 사용한 JSON 버킷 정책은 위 처럼 만들어서 넣었다. 이 부분은 처음에 어떻게 제작해야 하는지 몰라서 곤란했었는데, 폭풍 검색을 통해 django 프로젝트 진행 시 s3를 기초 세팅할 때 도움이 많이되는 영상을 찾았다.
Django를 사용하면서 AWS S3 초기세팅이 막막한 분들이 참고하면 굉장히 유용할 것 같다.
# AWS S3 Setting
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_REGION = env('AWS_REGION')
AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_QUERYSTRING_AUTH = False
IMAGE_URL = "https://%s.s3.%s.amazonaws.com/" % (AWS_STORAGE_BUCKET_NAME, AWS_REGION)
위의 값들 처럼 settings.py 파일 내에 세팅해 줬다. 나는 env 파일을 따로 만들어서 그 안에 값들을 중요 값들을 넣어두고 관리하고 있어서 위와 같은 방식으로 값들을 가져와줬다.
pip install boto3
pip install django-storages
위의 패키지를 설치해주고 settings.py 내에 INSTALLED_APPS
안에 추가해준다.
나는 일단 유저의 프로필 이미지를 바꿔주는 기능을 제작했다.
const file = (e.target.files as FileList)[0];
if (file) {
const formData = new FormData();
formData.append("files", file);
formData.append("id", myInfo.id + "");
api
.post(`${API_Path.PROFILE_IMAGE}?host_id=profile`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
dispatch(setMyInfo({ ...myInfo, profile_img: res.data.profile_img }));
})
.catch((error) => console.log(error));
}
위의 코드를 보면 이미지는 파일 자체를 새로 생성한 FormData 인스턴스에 담아서 데이터를 서버로 전송한다.
위의 path 부분의 host_id
부분은 S3에 이미지를 업로드할 때 넣어줄 폴더 명이다. S3내에 그 이름의 폴더가 없다면 자동 생성되니 없다고해서 문제가 되진 않는다.
class ProfileImageUpload(View):
def post(self, request):
try:
files = request.FILES.getlist('files')
host_id = request.GET.get('host_id')
s3r = boto3.resource('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
key = "%s"%(host_id)
for file in files:
file._set_name(str(uuid.uuid4()))
s3r.Bucket(AWS_STORAGE_BUCKET_NAME).put_object(Key=key+'/%s'%(file), Body=file, ContentType='image/jpeg')
user = User.objects.get(pk=request.POST['id'])
user.profile_img = ("%s/%s"%(host_id, file))
user.save()
return JsonResponse({"message": "success", "profile_img": str(user.profile_img)}, status=200)
except Exception as e:
return JsonResponse({"error": e})
위의 코드에서는 파일들을 getlist로
받고 있는데, 나는 여러개의 이미지를 받을 수도 있는 상황이 있을 것 같아 일단 getlist
받고 있는 거고 한 개의 파일만 받는다면, get
만 사용해도 된다.
아무튼! 받은 파일을 프론트에서 같이 넘겨준 파라미터에있는 host_id
와 함께 S3에 업로드하고 User 모델의 profile_img의 값은 host_id
와 파일 이름만 넣어서 저장해준다!
저 부분이 실행되면 실제 DB안에는 값이 이렇게 들어오게 된다.
S3 에는 위의 이미지처럼 profile 폴더 안에 이미지가 생성된다.
{myInfo.profile_img ? (
<img
src={`https://cardlogbucket.s3.amazonaws.com/${myInfo.profile_img}`}
alt=""
/>
) : (
<FaUserCircle />
)}
이제 내 정보안에 저장되어 있는 이미지를 가져와서 사용할 때는 위와 같은 방식을 사용하게되면 프로필 이미지가 있을 때는 이미지가 아주 잘 나오고! 없을 때는 아이콘으로 대체된다!
아주 잘 작동한다!