selected_related
다음과 같은 관계일 때,
select할 모델 객체가 역참조하는 single object(one to one, many to one)
정참조 외래키(foreign key)
Join된 테이블을 불러들이는 쿼리를 실행하여 한번의 쿼리만으로 모델에 참조된 모델들의 필드를 읽을 수 있다.
예시
장고문서에서 예시를 확인해보자
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 <- Person <- City의 참조관계가 있다.
# Hits the database with joins to the author and hometown tables.
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.
- selected_related를 사용하지않을때는 총 세번의 쿼리 갯수가 있다.(세번 데이터베이스 접근)
- select_related는 총 한번의 쿼리(JOIN)를 부름으로써 참조관계에 있는 필드들을 불러 읽을 수있다.
- 쿼리는 복잡해지지만 불러온 필드데이터값들이 캐시에 남아있기때문에 DB의 접근을 줄일 수 있다.
응용
djangopractice에는 다음과 같은 모델 릴레이션이 있다. Many(review) to one(restaruant)관계이다.
class Restaurant(models.Model): # Restaurant 라는 상점을 나타내는 모델을 정의
name = models.CharField(max_length=30) # 이름
address = models.CharField(max_length=200) # 주소
...
class Review(models.Model):
point = models.IntegerField(default=0)
comment = models.CharField(max_length=500)
# 식당 모델과의 릴레이션 정의,
# on_delete CASCADE로 지정하면 식당이 삭제되면 같이 삭제된다.
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
...
이러한 릴레이션 관계(Many to one)에서 한번의 호출만을 사용하여 Restaurant과 관련된 review데이터를 불러들일수 있다.
def review_list(request):
#reviews = Review.objects.all().order_by('-created_at')
reviews = Review.objects.select_related().all().order_by('-created_at')
paginator = Paginator(reviews, 10) # 한 페이지에 10개씩 표시
page = request.GET.get('page') # query params에서 page 데이터를 가져옴
items = paginator.get_page(page) # 해당 페이지의 아이템으로 필터링
context = {
'reviews': items
}
return render(request, 'third/review_list.html', context)
댓글 쓰기