[Django] - queryset vs get_queryset

오동훈·2023년 6월 18일
0

Django

목록 보기
22/23
post-custom-banner

1. 사건의 발단

우선 대충 아래와 같은 코드로 구성이 되어 있었는데, put으로 수정하면 수정된 데이터가 반환되지만 그 이후 전체에 대해 조회했을 때 수정된 데이터가 보이지 않는 이슈가 있었습니다.

class TravelViewSet(mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.DestroyModelMixin,
                    mixins.ListModelMixin,
                    GenericViewSet):
    queryset = Travel.objects.all().order_by('-id')
    serializer_class = TravelSerializer


    def list(self, request, *args, **kwargs):
        serializer = self.get_serializer(self.get_queryset(), many=True)
        data_response = {
            "message": "OPERATION_SUCCESS",
            "results": serializer.data
        }
        return Response(data_response)


    def update(self, request, pk):
        travel = self.get_object(pk)
        if not travel:
            return not_found_data

        serializer = self.serializer_class(travel, data=request.data, partial=True)
        if serializer.is_valid():
            updated_travel = serializer.save()
            results = {
                "message": "OPERATION_SUCCESS",
                "results": self.serializer_class(updated_travel).data
            }
            return Response(results)
        else:
            return operation_failure
            
            .
            .
            .

2. 문제 추정

1. DB 값 변경이 안됐나

처음에는 DB 값이 제대로 변경되지 않았나 싶어 데이터를 조회해보니 제대로 수정이 되어 있었습니다. 그래서 DB 추정 원인은 그대로 패스~

2. ListView에 캐싱이 자체적으로 되어 있나

그래서 그 다음에는 사용하고 있는 ListView에 대해 자체적으로 캐싱 기능이 있다고 추정하고 ListView 끝자락에 cache.clear()를 추가해 주었더니 기존과 다르게 정상적으로 나오는 것을 확인할 수 있었습니다.

아~ 이것은 캐싱 기능때문이구나 알아차렸고 그 이후 사용하고 있는 queryset 부분에서 캐싱 기능이 있겠구나 생각했습니다.

3. 확인을 위해 djdt 설치

djdt를 사용해 확인해보니 결과는 다음과 같았습니다.

서버 구동 이후 첫 request 요청에 대해서만 DB 조회했고, 이후 요청 건부터는 DB를 조회하지 않는 것을 확인할 수 있었습니다.

서버 구동 이후 첫 조회

서버 구동 이후 두 번째 이후부터의 상태

4. Django GenericAPIView

위의 내용을 확인한 이후 queryset이 어떻게 구성되어 있나 찾아보던 중 다음과 같은 주석을 확인할 수 있었습니다.

    # If you are overriding a view method, it is important that you call
    # `get_queryset()` instead of accessing the `queryset` property directly,
    # as `queryset` will get evaluated only once, and those results are cached
    # for all subsequent requests.

queryset - 서버 구동 이후 첫 request 요청에 대해서 DB 조회 후 캐시로 저장
get_queryset - 캐시 저장 없이 매 요청마다 DB 조회

DRF 공식문서에도 queryset은 DB를 한 번만 조회하니 필요한 경우 get_queryset()을 사용하라고 나와있습니다.
DRF 공식문서 - queryset

5. 결론

기본적으로 queryset을 선언해주되 최신의 DB 데이터가 필요한 상황이라면 get_queryset()을 사용하면 캐싱된 데이터로 인해 오류를 범하지 않을 수 있습니다.

class TravelViewSet(mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.DestroyModelMixin,
                    mixins.ListModelMixin,
                    GenericViewSet):
    queryset = Travel.objects.all().order_by('-id')
    serializer_class = TravelSerializer

    def list(self, request, *args, **kwargs):
        serializer = self.get_serializer(self.get_queryset(), many=True)
        data_response = {
            "message": "OPERATION_SUCCESS",
            "results": serializer.data
        }
        return Response(data_response)

이번에 queryset과 get_queryset의 명확한 차이를 새롭게 알게 되었습니다. 그렇다면 queryset 같은 경우 한 번만 조회하고 그 이후에 새롭게 조회되지 않는데 어떤 상황에서 이러한 기능을 사용할 수 있을지는 아직은 잘 모르겠습니다. 암튼 다들 이런 이슈 겪으면 빠르게 알아차리세요 히히~


참고자료 📩
queryset vs get_queryset
DRF 공식문서 - queryset

profile
삽질의 기록들🐥
post-custom-banner

0개의 댓글