장고에서 Annotate 와 기존 필드를 Union 하려면 좀 이상하게 작성해야한다.
결론적인 문제점은 Annotate 된 필드는 쿼리의 하위에 작성된다. Values 에 쓰인 순서대로 나왔으면 좋겠지만 그렇지 못한다.
가맹점쿼리 = 가맹점.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(유니온쿼리)
(
SELECT
id
status
name
addr as address
)
union
(
SELECT
id
address
name
null as status
)
id | status | name | address |
---|---|---|---|
1 | 운영중 | 가맹점1 | 가맹점주소... |
2 | 운영중 | 가맹점2 | 가맹점주소... |
1 | 협력사주소.. | 협력사1 | null |
2 | 협력사주소.. | 협력사2 | null |
협력사의 필드 순서가 이상하게 나오는 걸 알 수 있다.
유니온 쿼리의 순서를 보면 address
, status
의 순서가 Values 에 작성된 것과 다르다. 결론은 annotate 에 정의된 필드는 반드시 SELECT 절의 하위에 작성된다.
Annotate 된 필드는 SELECT 절의 하위에 나오게되니, 양쪽의 Annotate 필드를 맞추면 된다.
근데 여전히 문제가 하나 더 있다. address=F('address')
사용할 수 없다. Django 에서는 같은 이름의 필드가 이미 존재하면 annotate 하지 못하기 때문이다.
가맹점쿼리 = 가맹점.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(유니온쿼리)
(
SELECT
id
name
addr as address
status as _status
)
union
(
SELECT
id
name
address as _address
null as status
)
결과는 제대로 나오게된다. 근데 필드 이름이 문제가된다..