ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Django] orm distinct()
    Framework/Django 2022. 2. 22. 00:03

    django orm으로 개발하다가 컬럼의 중복을 제거하려고 distinct()를 사용하였다. 중복 제거 키워드인 distinct()인 사용하였다.

     

    TestService.objects.using("db").values("service_id")
    .filter(status="pending").distinct().order_by("-id")

     

    orm을 간단하게 해석하자면 TestService라고 하는 model 클래스에서 status가 pending인 service_id를 중복을 제거하여 출력하는 예제이다. 마지막 order by조건으로 id가 역순으로 출력이 되어야 한다.

    (id는 pk값이고, service_id는 fk이다.)

     

    해당 orm 코드를 sql언어로 바꾸어보면 다음과 같다.

    select distinct(service_id) from test_service where status='pending' order by id desc

    원하는 결과는 다음과 같다.

    service_id
    3
    2
    1

     

    그런데 출력을 해보면 다음과 같이 나온다.

    id service_id
    5 3
    4 1
    3 2
    2 2
    1 1

    ?????? 중복제거가 되지 않았다..

     

    왜 안될까를 생각해보았다.

    1.  id가 pk라서 django orm에서는 무조건 출력을 하는것일까?

    2. 내가 distinct()를 잘못 사용해서 그런것일까?

     

    1번은 말이 될 수도 있지만 만약 pk라서 무조건 출력이 된다면 distinct()에 의미를 퇴색되므로 말이 되지 않는다고 생각했다. 그래서 2번에 대한 해답을 찾기 위하여 공식문서를 한참 찾아보다가 distinct 괄호안에 특정 항목을 넣을 수 있는 것을 발견했다!

    역시 모르는건 공식문서!

    django.db.utils.NotSupportedError: DISTINCT ON fields is not supported by this database backend..

    했으나 다음과 같은 에러가 발생하였다..

     

    에러를 좀 찾아보니 mysql을 사용할때는 distinct 괄호안에 항목을 넣는것을 지원하지 않는다. PostgreSQL만 지원..

    https://stackoverflow.com/questions/54249017/distinct-on-fields-is-not-supported-by-this-database-backend/54249277

     

    결국 위와 같은 것은 해결법이 되지 않아서 또 한참을 찾았는 데.. 또 다시 공식문서가 해답을 주었다. 바로 저 예제 위에 해답이 있었다.

     

    Note를 살펴보면 order_by를 사용할경우 distinct()의 select 결과문이 원하는 대로 동작하지 않을 수 있다는 것이다!

    결국 order_by에서 id값을 넣어주었기에 id값 때문에 distinct()가 제대로 동작하지 않았다. 

    마지막에 적은 order_by항목을 제거하고 나면 원하는대로 값이 출력이 된다.

     

    결론

    django orm에서 distinct()를 쓸 때는 order_by를 조심히 사용하여야 한다. order_by()에 지정한 필드가 distinct()에 추가된다!

    + 공식문서를 제대로 꼼꼼하게 읽을 것!

     

     

    공식문서 참고 링크

    https://docs.djangoproject.com/en/4.0/ref/models/querysets/#django.db.models.query.QuerySet.distinct

Designed by Tistory.