쿼리셋은 실제로 데이터베이스에 접촉하지 않고도 생성, 필터, 분리, 대입될 수 있다.
쿼리셋이 평가 (evaluate) 되기 전까지는 데이터베이스 활동이 일어나지 않는다.
쿼리셋은 다음과 같은 경우에 평가된다.
쿼리셋을 순회하는 경우
쿼리셋은 순회가능 (iterable)
객체이며, 쿼리셋을 순회하는 순간 데이터베이스에 쿼리를 실행해 쿼리셋에 담긴 레코드들을 불러오게 된다.
for entry in Entry.objects.all():
print(entry.headline)
쿼리셋을 슬라이싱하는 경우
쿼리셋은 Python의 슬라이싱 문법을 사용해서 슬라이싱 할 수 있다.
Entry.objects.all()[:5]
위와 같은 경우에는 모든 레코드들의 쿼리셋에서 5개의 레코드만 가지는 쿼리셋을 새로 생성하여 리턴하며, 이 때 쿼리셋은 평가되지 않는다. 그러나 아래와 같이 스텝을 사용한 슬라이싱을 실행한 경우, 쿼리셋이 평가되며 그 결과를 리스트로 반환한다.
Entry.objects.all()[:5:2]
쿼리셋을 슬라이싱하는 경우 주의할 점은, 스텝을 사용하지 않은 슬라이싱이 평가되지 않은 새로운 쿼리셋을 리턴한다고 해서 여기에 추가적으로 필터를 적용하거나 하는 등의 추가적인 작업을 수행하는 것은 불가능하다. 이러한 명령은 SQL 문법으로 잘 번역되지 않을 뿐만 아니라 의미적으로도 정확하지 않기 때문이다.
쿼리셋을 피클링/캐싱 하는 경우
피클링/캐싱에 대한 자세한 내용은 다른 포스트를 참고하기 바란다. 여기서 알아야할 점은 피클링/캐싱을 하는 경우 데이터베이스에서 쿼리셋 결과를 읽어온다는 점이다.
repr()
을 사용하는 경우
쿼리셋에 repr()
함수를 적용하는 경우 쿼리셋이 평가된다. 이는 Python 인터렉티브 인터프리터에서 API를 사용해 쿼리셋을 가져온 다음 결과를 즉시 확인하고자 할 때를 위한 편의기능이다.
len()
을 사용하는 경우
쿼리셋에 len()
함수를 적용하는 경우 쿼리셋이 평가된다. 쿼리셋에 포함된 데이터의 개수를 리턴한다.
만약 실제 데이터는 필요하지 않고 그 개수만 확인하려는 경우 SQL 문의 SELECT COUNT(*)
를 사용하는 것이 훨씬 효율적이며, Django
에서는 이 명령을 실행하는 count()
함수를 제공한다.
list()
를 사용하는 경우
list()
함수를 통해 강제로 쿼리셋을 평가할 수 있다.
entry_list = list(Entry.objects.all())
쿼리셋을 검사(test) 하는 경우
bool()
, and
, or
, if
등으로 쿼리셋을 검사하는 경우 쿼리셋이 평가된다. 이 경우, 쿼리셋에 값이 하나라도 있으면 True
, 아니면 False
가 된다.
단순히 쿼리셋에 하나 이상의 값이 있는지를 확인하고 싶다면, exists()
를 사용하는 것이 효율적이다.
Reference
Django 공식문서: https://docs.djangoproject.com/en/1.11/ref/models/querysets/#when-querysets-are-evaluated