Django ninja를 활용하여 프로젝트 개발을 잘 하고 있었는데 게시글 수정을 위한 API를 코딩하던 중 문제가 발새했다.
patch 메서드를 써서 게시글을 수정하는 API였는데 회원정보를 수정하는 API는 이 방법으로 아무 문제 없이 잘 되었다.
@router.patch("/{user_id}", response={200: SuccessOut, 404: NotFoundOut}, auth=[AuthBearer()])
def modify_user_info(request, user_id: int, payload: ModifyUserIn):
그래서 비슷하게 만들면 똑같이 잘 되겠지 하고 리퀘스트 바디에 업로드 파일을 받을수있도록 추가해서 만들었는데 아무리 테스트 해봐도 계속 422 에러가 떴다.
@router.patch("/{post_id}", response={200: SuccessOut, 400: BadRequestOut}, auth=AuthBearer())
def modify_post(request, post_id: int, body: ModifyPostIn = Form(...), file: UploadedFile = None):
아무리 제대로 된 값을 입력해도 리퀘스트 바디 스키마(ModifyPostIn)의 유효성 검사를 통과하지 못해 응답코드 422, 밸류 에러 리스폰스가 나왔다.
class ModifyPostIn(Schema):
subject: Optional[str]
content: Optional[str]
구글링해보니 ninja 깃헙 저장소의 이슈 포스팅으로 이미 문제가 제기된 부분이지만 이후에 패치가 되지 않았다. 이건 ninja보다는 Django 문제라서 그런것 같다.
문제 원인:
해결방법:
request._load_post_and_files()
로 form-data에 게시글 수정 데이터와 파일을 채워놓고 다시 원래 메서드(PUT 또는 PATCH)로 돌려놓는 미들웨어를 추가해서 해결했다.미들웨어 코드
문제는 django 미들웨어 관리를 해본 적이 없어서 어떻게 해야 링크에 나온 코드를 미들웨어로 만들 수 있는지 몰랐다. 그래서 또 구글링을 해보니 비슷한 케이스가 있었다
MiddlewareMixin 클래스를 상속받아서 코드를 집어넣고 정해진 형식대로 미들웨어를 추가해주면 되는 것이었다. 덕분에 MiddlewareMixin이라는 클래스가 있다는 것과 활용방법을 배웠다.
# cores/middleware.py
from django.utils.deprecation import MiddlewareMixin
class PutPatchWithFileFormMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.method in ("PUT", "PATCH") and request.content_type != "application/json":
if hasattr(request, '_post'): # post 데이터 삭제
del request._post
del request._files
try:
initial_method = request.method
request.method = "POST" # 리퀘스트 메서드를 POST로 임시 변경
request.META['REQUEST_METHOD'] = 'POST'
request._load_post_and_files() # 이 부분이 핵심
request.META['REQUEST_METHOD'] = initial_method # 원래 메서드로 되돌림
request.method = initial_method # 원래 메서드로 되돌림
except Exception:
pass
# settings.py
# MIDDLEWARE 리스트에 다음 값 추가
# "폴더명.파일명.클래스명"
"cores.middleware.PutPatchWithFileFormMiddleware"
미들웨어가 꼭 클래스여야 할 필요는 없고 함수로도 가능하다.
단 팩토리 메서드 패턴이 적용된 함수여야 한다.