-
Django 에서 Annotate 와 Union 을 함께 사용할 때 생기는 문제기술/Django 2021. 9. 24. 18:32
Django 에서 annotate 로 추가한 필드와 기존 필드들을 Union 후 같이 사용할 때 몇가지 이상한 동작이 있습니다.
똑같은 컬럼을 annotate 했지만 컬럼의 결과에 다른 컬럼의 값이 들어있는 문제가 발생했습니다.
파란색 네모가 status 값인데 일부가 address 에 존재하고
빨간색 네모가 address 값인데 일부가 status 에 존재했습니다.
동작하지만 원하는 결과가 나오지 않는 코드
Python 코드
가맹점쿼리 = 가맹점.objects.annotate( address=F('addr'), ).values( 'pk', 'status', 'address', 'name', ) 협력사쿼리 = 협력사.objects.annotate( status=Value(None, output_field=models.CharField()), ).values( 'pk', 'address', 'name', ) 유니온쿼리 = 가맹점쿼리.union(협력사쿼리) print(유니온쿼리)
SQL 결과
( SELECT id status name addr as address ) union ( SELECT id address name null as status )
결과 테이블
SQL Union 쿼리의 순서를 보면 address, status 의 순서가 ORM 의 Values 로 작성한 순서와는 다르게 나왔습니다.
즉, annotate 에 정의된 필드는 반드시 SELECT 절의 하위에 작성되었습니다.
해결책
annotate 된 필드는 SELECT 절의 하위에 나오게되니 모든 필드를 annotate 를 사용하여 순서를 제어해주면 됩니다.
여기서 주의해야 할 문제가 하나 더 있는데 Django 에서 이미 존재하는 필드의 이름과 동일한 이름으로 annotate 를 사용할 수 없습니다.
Python 코드
가맹점쿼리 = 가맹점.objects.annotate( address=F('addr'), _status=F('status'), # 이미 있는 필드를 재정의 하지 않기 위해 이름을 다르게 지었습니다. ).values( 'pk', 'address', 'name', ) 협력사쿼리 = 협력사.objects.annotate( _address=F('address'), # 이미 있는 필드를 재정의 하지 않기 위해 이름을 다르게 지었습니다. status=Value(None, output_field=models.CharField()), ).values( 'pk', '_address', 'name', ) 유니온쿼리 = 가맹점쿼리.union(협력사쿼리) print(유니온쿼리)
SQL 결과
( SELECT id name addr as address status as _status ) union ( SELECT id name address as _address null as status )
'기술 > Django' 카테고리의 다른 글
Django Filters 에서 하나의 Key를 가지고 여러 값 필터하기 ( MultipleFilter ) (0) 2021.09.24 Django 에서 String datetime 을 aware 한 datetime 으로 변경하는 방법 (0) 2021.09.24 Django 에서 Chain 필터 시 추가적인 테이블 JOIN 방지하기 ( + _next_is_sticky ) (0) 2021.09.24 Django Manager, Queryset (1) 2021.09.24 Django 에서 Generic ForeignKey 를 사용을 권장하지 않는 이유 (0) 2021.09.24