Issue: QueryDict instance is immutable

KimJiHong·2023년 12월 9일
1

Issue

목록 보기
2/7
post-thumbnail

Issue

나는 게시글에 대한 onwer 필드를 User 모델과의 Foreign Key 관계로 게시글과 사용자 간에 1:N 관계를 형성했다.

# models.py
class PostModel(models.Model):
    # FK (User 모델과의 관계 설정)
    owner = models.ForeignKey(User, on_delete= models.CASCADE, related_name= "post_owner")
    # ...

그리고 게시글 리소스의 생성(CREATE) 및 업데이트(UPDATE) 작업에서 클라이언트에서 onwer 정보 조작을 방지하기 위해, view에서 request 데이터에 owner 정보를 추가하도록 구현했다.

# views.py
class PostListCreateAPIView(generics.ListCreateAPIView):
	# ...
    def create(self, request, *args, **kwargs):
        request.data['owner'] = request.user.pk
        return super().create(request, *args, **kwargs)

하지만, DRF의 APITestCase를 통해 API End-Point 테스트 코드를 작성하고 있는 도중

CREATE 작업과 UPDATE 작업에서만 아래와 같은 오류가 발생했다.

# test case
def test_create_post_success(self):
	# ...
    response = self.client.post(
        path= f'{BASE_API_URL}/posts',
        data= {
            "title": "게시글 제목",
            "contents": "게시글 내용"
        }
    )
# Out-Put: error Messages
AttributeError: This QueryDict instance is immutable

Search My Issue on Google

나는 구글에 내 오류를 검색해서 나와 같이 request.data에 접근할 때

같은 오류가 발생해 질문한 게시글이 있었다.

질문자도 똑같이 request.data를 수정할 때만 문제가 발생해 질문을 올린 것 같다.

해당 Issue의 해결책을 확인하기 위해 답변 내용을 확인해봤다.

답변 내용은 APIClient가 format을 지정하지 않으면, 기본 데이터 형식인 multipart로 전송해 request가 딕셔너리가 아닌 불변 객체 QueryDict으로 받아 발생하는 오류라고 한다.
(감사합니당~)

그래서 실제로 view에서 request.data를 찍어봤다.

# class PostListCreateAPIView(generics.ListCreateAPIView):
#     ...
#     def create(self, request, *args, **kwargs):
#         print(request.data)

QueryDict: {'title': ['게시글 제목'], 'contents': ['게시글 내용']}>

format을 지정하지 않으면, default 값인 multipart/form-data 형식으로 데이터를 전송 있었다.

그로 인해, QueryDict를 변경하도록 구현한 CREATEUPDATE 작업에서만 오류가 발생한 것이다.

Solution.1 - Set format

첫번째 해결책으로는 APIClient의 데이터 전송 형식을 JSON으로 지정하는 것이다.

# test case
def test_create_post_success(self):
	# ...
    response = self.client.post(
        path= f'{BASE_API_URL}/posts',
        data= {
            "title": "게시글 제목",
            "contents": "게시글 내용"
        },
        format= 'json' # 데이터 형식을 json 형식으로!
    )

만약에, 파일 업로드시와 같이 multipart/form-data를 사용해야할 경우가 발생하면
똑같이 QueryDict를 수정 해야함으로 다시 같은 오류가 발생할 것이다.

그래서 나는 두번째 방법으로 테스트 코드를 작성 했다.

Solution.2 - '_mutable' flag on the QueryDict

두번째 해결책은 _mutable 플래그로 QueryDict를 수정할 수 있도록 지정하는 방법이다.

# views.py
class PostListCreateAPIView(generics.ListCreateAPIView):
    # ...
    def create(self, request, *args, **kwargs):
        setattr(request.data, '_mutable', True) # QueryDict 수정 허용
        request.data['owner'] = request.user.pk
        return super().create(request, *args, **kwargs)

StackOverFlow에서 답변한 것처럼 multipart 형식을 필연적으로 사용해야 할 때

_mutable 플래그로 QueryDict를 수정할 수 있도록 정의해주면 된다.

Solution TEST

테스트 통과!

Ref.

https://stackoverflow.com/questions/61277462/attributeerror-this-querydict-instance-is-immutable-for-test-cases

profile
https://h0ng.dev

0개의 댓글

관련 채용 정보