• Django QuerySet Value 에러 해결하기

    2021. 5. 10.

    by. Jacob Lee

    728x90

     


     

    에러 해결하기

    비즈니스 로직을 짜면서 항상 실수하고 많이 접하는 에러가 쿼리셋 슬라이싱 에러이다.

    구글링을 해보아도 몇 개의 글 말고는 찾아보기 힘든데, 기억할 겸 한번 정리해보려고 한다.

    문제의 에러는 다음과 같다.

    The QuerySet value for an exact lookup must be limited to one result using slicing.

    해석해보면, 정확한 조회를 위한 쿼리셋 밸류는 슬라이싱을 활용한 하나의 결과로 제한되어야 한다는 것이다.

     

    풀어서 말해보면, 장고에서 filter 메소드는 SQL의 WHERE절로서, 조건에 맞는 한 개 이상의 쿼리 셋을 리턴하는데, 이때 조건으로 쿼리셋을 사용하면 위와 같은 에러가 발생한다.

    로직을 짜다보면, 이미 가져온 특정한 쿼리셋으로 유저의 쿼리셋을 뽑는다던지 다른 테이블에 접근을 하는 경우가 많은데, 이럴 때 항상 발생하는 에러이다.

     

    예를 들면 아래와 같은 상황이 있다고 가정해보자.

    # 매개변수로 받아온 데이터로 필터링한 특정 쿼리셋을 특정 변수에 저장
    group = Group.objects.filter(object_id=object).values('id')
    
    # 쿼리셋으로 필터링을 할 때 에러가 발생
    active_users = User.objects.filter(
        group_id = group,
    ).values('user_id')

    받아온 매개변수로 특정 테이블을 필터링한 쿼리셋 결과를 변수에 저장한 후, 다른 테이블을 필터링할 때 발생한다.

    즉, 쿼리셋을 쿼리셋으로 필터링 하려고 하면 발생하는 에러이다.

     

    이때 해결할 수 있는 방법은 장고의 in field lookup을 사용해주는 것이다.

    장고의 in은 튜플, 리스트, 쿼리셋 등 반복 가능한 객체를 조회한다. SQL문에서의 WHERE IN과 같은 역할을 한다.

     

    in을 사용해서 아래와 같이 쿼리셋에 접근하면 에러를 해결할 수 있다!

    active_users = User.objects.filter(
        group_id__in = group,
    ).values('user_id')

     

     

    In 필드 조회를 사용할 때 주의해야 할 점

    장고에서 in을 사용할 때 주의해야 할 점이 하나 있다.

    장고 공식 문서 예제로 잘 설명이 돼있는데, 쿼리셋으로 __in 조회를 사용해 values나 values_list를 사용할 때는 하나의 필드만 뽑아내야 한다는 것이다.

    inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
    entries = Entry.objects.filter(blog__name__in=inner_qs)

     

    둘 이상의 필드를 리턴하기 위해 다음과 같이 사용하면 에러가 발생한다.

    # Bad code! Will raise a TypeError.
    inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
    entries = Entry.objects.filter(blog__name__in=inner_qs)

     

    728x90

    댓글