[ TIL ] multipart/form-data

Hailee·2020년 12월 31일
2

[ TIL ]

목록 보기
31/40
post-thumbnail

👉🏻 [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)

우선, 지금의 회원가입 로직은 이런식으로 작성해뒀다.
아마 대대적인 수정이 들어갈 것 같다.

회원 가입과 동시에 프로필 사진을 지정할 것이라고 생각했는데,
보통의 웹사이트들이 그렇게 하지 않기 때문..!!!

다시 원래 상태로 되돌려야겠다.

profile
웹 개발 🐷😎👊🏻🔥

0개의 댓글