-
[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만 지원..
결국 위와 같은 것은 해결법이 되지 않아서 또 한참을 찾았는 데.. 또 다시 공식문서가 해답을 주었다. 바로 저 예제 위에 해답이 있었다.
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