지난번에 작성했던 '테이블(모델)의 JOIN(1)'의 경우 너무 가볍게 보기도 하고 거기서 언급했듯 스스로도 이해를 못했기 때문에 prefetch_related()와 select_related() 각각의 메소드 사용법을 조금 더 살펴보겠습니다. 이번 포스팅에서는 둘 중 먼저 select_related()의 사용 대해 다뤄보고자 합니다.
간단 사용법
쿼리를 실행했을 때에 지정된 외래 키의 개체도 함께 가져온다. 이를 통해 DB에 접근하는 횟수를 줄일 수 있다. 사용예에 대해서 살펴보자면, 첫 번째 코드를 두 번째로 코드로 변경할 수 있다.
# DB에 접근
e = Entry.objects.get(id=5)
# 아직 DB를 건들이고 있다.
b = e.blog
# DB에 접근
e = Entry.objects.select_related('blog').get(id=5)
# 미리 DB에서 얻어낸 객체를 참고하므로 DB를 계속해서 접근하지 않는다.
b = e.blog
조금 더 자세히 살펴보기
● 외래키의 외래키를 얻을 경우
다음과 같이 도시, 작가, 기사 모델이 있다고 가정하자.
from django.db import models
class City(models.Model):
# ...
pass
class Author(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Entry(models.Model):
# ...
author = models.ForeignKey(Author, on_delete=models.CASCADE)
이 상황에서 기사의 모델의 고향(hometown)을 알고 싶은 상태이다. 먼저 select_related를 사용하지 않는 패턴을 살펴보자.
b = Entry.objects.get(id=4) # DB에 접근
p = b.author # DB에 접근
c = p.hometown # DB에 접근
3번 DB에 접근하게 된다. 계속해서 select_related를 사용한 패턴은 아래와 같다.
# 한 번의 쿼리로 author와 hometown 테이블로 부터 객체를 취득한다.
b = Entry.objects.select_related('author__hometown').get(id=4)
p = b.author # 취득한 객체를 참고
c = p.hometown # 취득한 객체를 참고
select_related를 사용하면 DB에 접근하는 것은 1번 뿐이다.
● 관계 테이블의 리스트를 클리어
selecte_related로 취득한 관계 테이블의 객체를 쿼리셋으로부터 클리어하고 싶을 때가 생길 수 가 있는데, 이때 키워드 인수에 None을 넣어 실행하면 된다.
without_relations = queryset.select_related(None)
● 여러 개의 select_related()를 엮어 사용할 때
select_related()로 여러 테이블의 관계를 형성하고 싶을 때 아래와 같이 작성하는 것이 아니라
select_related('foo').select_related('bar')
이와 같이 작성한다.
select_related('foo', 'bar')
● 관계 테이블의 객체가 존재하지 않는 경우
어떤 상황인지에 대해서는 조금 더 자세히 설명하도록 하겠다.
# 기사의 작가를 확인하면
entry.author
# 작가는 "고릴라"이다.
>> <Author: 고릴라>
entry.author.pk
>> 1
# "고릴라"를 삭제한다.
Author.objects.get(pk=1).delete()
entry = Entry.objects.select_related('author').first()
entry
<Entry: 고릴라입니다. 블로그 시작합니다.>
entry.author == None
True
객체가 삭제되었음에도 QuerySet를 실행시키면 에러가 아닌 None이 리턴된다는 사실을 잊지말자.
● 인수를 지정하지 않는 경우
인수를 지정하지 않으면 null = False의 외래키만 취득대상이 된다. 기본적으로 인수를 명시적으로 지정하도록 하자.
● 관계 테이블의 데이터를 얻고 싶은 경우
아무튼 관계 테이블의 데이터가 필요한 경우 __(언더 스코어 2개)를 사용하는 표현을 쓴다. 고릴라 객체의 name과 description을 취득해보자.
entry = Entry.objects.filter(pk=1).select_related(
'author'
).values('author__name','author__description')
>> <AuthorQuerySet [{'author__name': '고릴라', 'author__description': '와일드합니다.'}]>
참고자료
'IT > WEB' 카테고리의 다른 글
XPATH 사용법·작성법 (0) | 2021.01.13 |
---|---|
[Django] 테이블(모델)의 JOIN(3) ; prefetch_related() (0) | 2020.11.18 |
[Vue.js] Vue.js 입문 (1) ; 기본 구문 (0) | 2020.11.13 |
[Django] 테이블(모델)의 JOIN(1) (0) | 2020.10.21 |
[JavaScript/jQuery] 코드 리뷰 내용 정리 (2) (0) | 2020.10.06 |