👉🏻 [dJango] multipart/form-data
👉🏻 HTTPie file-upload-forms
프론트에게서 넘겨받은 데이터를 가져올 때 쓰던 방식은 보통 json.loads(request.body)
였다.
request의 body부분에서 데이터를 가져오는 것!
하지만 왜인지, HTTPie로 form으로 넘어오는 데이터로 확인을 해보니 전혀 못넘어오고있는 것이 아닌가.
http -f localhost:8000/user/signup phone_number='01011111111' nickname='김영일' email='abc01@naver.com' profile_picture@~/westudy/증명사진.jpeg
혹시나 해서 data = request.POST
로 넘어오는 데이터에서 확인을 해보니 성공적으로 데이터를 얻어올 수 있었다.
HTTPie로 테스트하는 코드에서는 달라지는 것이 없는데, 첨부파일 하나가 추가되었다고 데이터를 받는 방식이 바뀐다는게 너무 헷갈렸다.
검색을 해보았고, 내가 지금 겪고있는 상황에 대한 단비같은 글을 발견할 수 있었다.
multipart는 MIME type이 개별적인 파트로 나누어지는 것을 말한다. request의 body에 여러 가지의 content_type을 담고 싶을 때 사용하게 된다. 그렇다보니 장고에서 일반적으로 사용하던 request.body는 사용할 수 없게 된다.
request.FILES['키값']
으로 파일들을 통신할 수 있고request.POST['키값']
으로 파일이 아닌 json 데이터 등을 통신할 수 있다.
👉🏻 포스트맨이나 httpie로 integration test를 진행할 때도 파일은 파일대로, json 데이터는 텍스트화해서 따로 보내게 된다.
이 상황에 대해서 멘토님께 질문을 드렸더니 2가지 방법이 있다고 하셨다.
프론트로부터 multipart/form-data
로 받되, 첨부파일과는 별개로, 다른 텍스트 데이터들은
프론트에서 json데이터로 변환한 뒤 multipart/form-data
내부에 json 데이터를 넣은 형식으로 보내주는 것
첨부파일은 multipart/form-data
로, 다른 텍스트 데이터들은 그냥 json 형식으로 2번의 요청을 통해 각각 넘겨받도록 하는 것!
이 두가지 방법이 잘 이해가 되지 않았는데, 구글링을 통해 찾은 저 블로그에서 어느 정도 감이 왔다.
{
chapters : [
{
chapter1 : 블라블라,
images : [
파일1,
파일2,
파일3
]
},{
chapter2 : 블라블라,
images : [
파일4,
파일5
]
}
]
}
원래 내가 생각했던 것도 대략 👆🏻 이런식으로 올 것이라고 생각했다.
하지만, 실제로는 이러한 식으로 데이터가 넘어오고 있는 것!👇🏻👇🏻
body = {
chapters : [
{
chapter1 : 블라블라,
},{
chapter2 : 블라블라,
}
]
}
files = [파일1,파일2,파일3,파일4,파일5]
json데이터를 갖고 있는 key값과 파일들을 담고 있는 키값이 따로따로 전달된다고 생각하면 된다. 그래서
request.POST['body']
는 json 데이터를,request.FILES['files']
는 파일을 전달 받을 수 있게 되는 것이다.
결국은, 각각 넘어온 데이터(json 데이터, 첨부파일)를 잘 출력해서 볼 수 있었다.
#회원가입
class SignUpView(View):
def post(self, request):
try:
data = request.POST
atch_file = request.FILES
if data:
phone_number = data['phone_number']
nickname = data['nickname']
email = data['email']
if str(phone_number[:3]) != '010':
return JsonResponse({'message': 'INVALID_PHONENUMBER'}, status=400)
if len(str(phone_number)) != 11:
return JsonResponse({'message': 'INVALID_PHONENUMBER_LENGTH'}, status=400)
if User.objects.filter(phone_number = phone_number).exists():
return JsonResponse({'message': 'DUPLICATED_PHONENUMBER'}, status=409)
if User.objects.filter(nickname = nickname).exists():
return JsonResponse({'message': 'DUPLICATED_NICKNAME'}, status=409)
if User.objects.filter(email = email).exists():
return JsonResponse({'message': 'DUPLICATED_EMAIL'}, status=409)
if atch_file:
profile_picture = atch_file.get('profile_picture')
User.objects.create(
phone_number = phone_number,
nickname = nickname,
profile_picture = profile_picture,
email = email
)
return JsonResponse({'message': 'SUCCESS'}, status=201)
except ValidationError:
return JsonResponse({'message': 'INVALID_PHONENUMBER'}, status=400)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
우선, 지금의 회원가입 로직은 이런식으로 작성해뒀다.
아마 대대적인 수정이 들어갈 것 같다.
회원 가입과 동시에 프로필 사진을 지정할 것이라고 생각했는데,
보통의 웹사이트들이 그렇게 하지 않기 때문..!!!
다시 원래 상태로 되돌려야겠다.