221223 TIL

haremeat·2022년 12월 23일
0

Django

목록 보기
13/16
post-thumbnail
post-custom-banner

태그 기능 만들다가 마주한 오류.

내가 만든 태그 기능은 한 작업물당 태그를 붙이는 방식이 아니라

filtering을 거쳐서 나온 목록들 여러개에 한번에 태그를 붙일 수 있는 기능이다.

그래서 view의 filtered_queryset에 바로 접근하기 위해 FilteredQuerySetMixin이라는 class를 serializer에 override해 사용하고 있었다.

FilteredQuerySetMixin이 하는 일은 오로지 view에서 filtered_queryset을 받아오고, 만약 데이터가 존재하지 않으면 처리할 수 있는 객체가 없다고 에러 메시지를 내뱉는 간단한 용도였다.

문제가 생긴 건 init의 view = kwargs['context']['view'] 이 부분이었다.

def __init__(self, *args, **kwargs):
  view = kwargs['context']['view']
  self.filtered_queryset = view.filter_queryset(view.get_queryset())
  super().__init__(*args, **kwargs)

이상하게도 자꾸 ‘view’를 찾을 수 없다고 Keyerror가 뜨는 것이다.

분명히 ViewSet에서 보내주는데 어째서 …?

디버깅해보니

init 에 요청이 들어오는 건 총 두 번.

첫 번째 요청에서는

정상적으로 ViewSet을 가져온다.

하지만 두 번째 요청에서는 ’view’를 가져오지 못한다.

그렇다면 두 번째 요청은 언제 들어오며 왜 들어오는가?

왜 두 번째 요청부터는 view를 받아오지 못하는가?

버그 원인

전에도 태그 적용 기능은 만든 적이 있지만

그때는 이 버그를 찾지 못했던 이유가

마침 그때는 리스트를 필터링할 때 ordering 필터를 사용하지 않았기 때문이다.

rest framework의 OrderingFilter를 사용할 때는 serializer를 통해 FilteredQuerySetMixin의 init을 호출한다. 두 번째 요청의 정체는 이거였다. 그 때는 view를 거치지 않기 때문에 당연히 kwargs['context']에는 ‘view’가 없으니 오류가 나는 것.

해결방법

def __init__(self, *args, **kwargs):
    try:
        view = kwargs['context']['view']
        self.filtered_queryset = view.filter_queryset(view.get_queryset())
    except KeyError:
        self.filtered_queryset = None
    super().__init__(*args, **kwargs)

이렇게 try except로 감싸주면 해결.
사실 해결방법 자체는 말도 안 되게 쉽지만
왜 이런 오류가 일어나는지 정확한 원인 찾기,
어떻게 해결하는 게 가장 옳은 방식일지 고민하기
요즘 이 두 가지를 많이 훈련중이다.
예전에는 오류 해결하기 급급했음...

profile
버그와 함께하는 삶
post-custom-banner

0개의 댓글