해당 메소드는 DB에서 filter
를 통해 원하는 조건의 데이터 유무에 따라 True
, False
를 반환해준다. QuerySet은 아니다. 특정 조건에 대한 이벤트나 로직을 처리할 때 많이 쓰인다.
역순으로 반환한다. 즉, 쿼리셋의 순서를 반대로 바꿔버린다.
my_queryset.reverse()[:5]
my_queryset이 기존에 갖고 있는 정렬 순서를 .reverse()
가 반대로 바꾸고 처음부터 5개의 데이터를 슬라이싱한다. 이는 초기 데이터에서 마지막 5개를 꺼내는 효과가 있다.
.reverse()
는 파이썬의 seq[-5:]
과 같은 효과를 내지만, 장고에서는 슬라이싱에서 음수를 지원하지 않기에 같은 방식으로 동작하지 않는다. 또한 .reverse()
는 QuerySet이 순서가 정의되어 있을 때만 효과가 있다.(기본 순서를 정의하는 모델에 대해 쿼리하거나 order_by()
를 사용할 때) 정의된 순서가 없는 경우에는 효과가 없다.
ForeignKey나 OneToOneField에 사용가능하다. 조금 더 복잡한 쿼리를 사용하지만 데이터베이스에 한 번만 접근하면 캐싱하기 때문에 퍼포먼스를 향상시킬 수 있다. select_related
는 쿼리를 실행할 때 추가적인 관련 객체 데이터를 선택해서 외래키 관계를 팔로우 할 QuerySet을 반환한다. 더 복잡한 쿼리를 갖고오도록 부추기지만, 외래키 관계를 사용할 경우 DB쿼리가 필요하지 않음을 의미한다.
# Hits the database.
e = Entry.objects.get(id=5)
# Hits the database again to get the related Blog object.
b = e.blog
위의 코드 두 줄은 실행하는 동안 각각 데이터베이스에 접근해야 한다.
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
select_related
로 'blog' 필드에 한 번 접근했기에 이미 캐싱이 되었고, e.blog에 접근할 때 데이터베이스를 거치지 않아도 된다.
# 객체의 QuerySet과 select_related() 함께 사용해보자
from django.utils import timezone
# 공개 예정인 항목이 있는 모든 블로그 찾기
blogs = set()
for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
# select_related()가 없으면 각각에 대한 데이터베이스 쿼리를 만 항목에 대한 관련 블로그를 가져오기 위해 각 루프 반복에 대한 DB 쿼리가 된다.
blogs.add(e.blog)
#`filter()` 나 `select_related()` 의 연결 순서는 상관없다.
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
외래키를 쿼리하는 것과 비슷한 방식으로 외래키를 따를 수 있다.
# models
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
Book.objects.select_related('author__hometown').get(id=4)
# 관련 Person과 관련 City가 캐시된다.
# author와 hometown 테이블에 조인하여 DB를 히트한다.
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
이 경우도 마찬가지이다. 위에서는 select_related
로 이미 author 객체 형태를 관리하는 모델에 접근이 이뤄져서 캐싱이 되었다. 이후에 author와 관련된 데이터에 대해서는 데이터베이스를 거치지 않아도 된다.
위에서도 설명했다싶이 select_related()
는 ForeignKey나 OneToOneField 관계를 참조할 수 있다. 또한 select_related()
을 전달된 필드 리스트에서 OneToOneField의 역방향도 참조할 수 있다. 즉, OneToOneField를 필드가 정의된 객체로 다시 이동할 수 있다.
>>> without_relations = queryset.select_related(None)
# QuerySet에서 select_related의 이전 호출에 의해 추가된
# 관련 필드 리스트를 지워야 하는 경우 매개 변수로 None을 전달한다.
# select_related를 체이닝하여 콜하는 경우
# 둘은 같다.
select_related('foo', 'bar') == select_related('foo').select_related('bar')