- django의 objects가 데이터베이스에 접근 시 foreign key가 설정되어 있는 테이블들까지 조회하는 메소드
- SQL의
join
- OneTonOneField 관계 그리고 정방향으로 참조하는 형태로 조회한다
- 매개변수로는 참조키를 지정한다
models.py
class City(models.Model):
name = models.Charfield(max_length=100)
class Meta:
db_table = 'CITY'
class Person(models.Model):
name = models.Charfield(max_length=100)
city = models.ForeignKey(City, on_delete=models.CASCADE)
class Meta:
db_table = 'PERSON'
class PersonInfo(models.Model):
address = models.Charfield(max_length=300)
zipcode = models.Charfield(max_length=6)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
class Meta:
db_table = 'PERSONINFO'
CITY table
id | name(이름) |
---|
1 | Seoul |
2 | Suwon |
3 | Daejeon |
4 | Jeonju |
5 | Yeosu |
6 | Busan |
7 | Jeju |
... | ... |
PERSON table
id | name(이름) | city_id |
---|
1 | Kim | 1 |
2 | Lee | 1 |
3 | Park | 2 |
4 | Jeong | 3 |
5 | Hong | 6 |
6 | Hwang | 7 |
... | ... | ... |
PERSONINFO table
id | address(이름) | zipcode | person_id |
---|
1 | 서울특별시 은평구 | 111111 | 1 |
2 | 서울특별시 송파구 | 222222 | 2 |
3 | 경기도 수원시 | 333333 | 3 |
4 | 대전광역시 | 444444 | 4 |
5 | 부산광역시 | 555555 | 5 |
6 | 제주도 | 666666 | 6 |
... | ... | ... | ... |
>>> person = Person.objects.get(id=1)
>>> person_city = person.city
>>> person_city
<City: City objects (1)>
>>> person_city.name
Seoul
select_related()
가 없으면 Person에서 objects를 통해 queryset을 구하고, 그 queryset에서 참조키인 city
를 참조해야만 person의 city값을 확인할 수 있다
>>> person_city = Person.objects.select_related('city').filter(id=1)
<Person: Person object (1)>
>>> person_city.city.name
Seoul
select_related()
사용 시 참조키인 city
를 매개변수로 지정하고 queryset를 반환한다
- 반환된 queryset에서 city의 값을 확인할 수 있다
>>> person_city = Person.objects.select_related('city').filter(id=1)
<Person: Person object (1)>
>>> str(person_city.query)
'SELECT `PERSON`.`id`, `PERSON`.`name`, `PERSON`.`city_id`, `CITY`.`id`, `CITY`.`name` FROM `PERSON` INNER JOIN `CITY` ON (`PERSON`.`city_id` = `CITY`.`id`) WHERE `PERSON`.`id` = 1'
select_related()
를 사용 시 해당 참조되는 컬럼(참조키) 기준으로 INNER JOIN
하는 것을 확인할 수 있다
select_related()
와 같이 foreign key가 설정되어 있는 테이블에서 사용하는 메소드
- OneTonOneField, ManyToManyField, ManyToOneField 관계 그리고 역방향으로 참조하는 형태로 조회한다
models.py
에서 ManyToManyField
또는 relate_name
매개변수로 지정된 키들을 참조해서 사용한다
- query를 확인해보면 역 참조되는 테이블과 참조하고 있는 테이블 각각 쿼리가 2번 실행된다.
- 테이블의 row수의 따라 참조 구성에 따라 query lazy 현상이 일어날 수 도 있음.
- 따라서 왠만하면
select_related()
사용 권장.
models.py
class Person(models.Model):
name = models.Charfield(max_length=100)
city = models.ForeignKey('City', on_delete=models.CASCADE)
language = models.ManyToManyField('Language', through='PersonLanguage')
class Meta:
db_table = 'PERSON'
class Language(models.Model):
name = models.Charfield(max_length=100)
class Meta:
db_table = 'LANGUAGE'
class Person_Language(models.Model):
person = models.ForeignKey('Person', on_delete=models.CASCADE)
language = models.ForeignKey('Language', on_delete=models.CASCADE)
class Meta:
db_table = 'PERSON_LANGUAGE'
PERSON table
id | name(이름) | city_id |
---|
1 | Kim | 1 |
2 | Lee | 1 |
3 | Park | 2 |
4 | Jeong | 3 |
5 | Hong | 6 |
6 | Hwang | 7 |
... | ... | ... |
LANGUAGE table
id | name(이름) |
---|
1 | Korean |
2 | English |
3 | Japanese |
4 | Chinese |
... | ... |
PERSON_LANGUAGE table
id | person_id(이름) | language_id |
---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 2 | 1 |
4 | 3 | 1 |
5 | 4 | 4 |
6 | 5 | 2 |
... | ... | ... |
>>> person = Person.objects.get(id=1).values()
>>> person
<QuerSet [{'id': 1, 'name': 'Kim', 'city_id': 1}]>
>>> person = Person.objects.get(id=1)
>>> person_language = Person_Language.objects.filter(person_id=person.id)
<QuerSet [<Person_Language: Person_Language objects (1)>, <Person_Language: Person_Language objects (2)>]>
>>> person_language.language.values()
<QuerSet [{'id': 1, 'name': 'Korean'}, {'id': 2, 'name': 'English'}]>
>>> person_language = Person.objects.prefetch_related('language').filter(id=1)
>>> person_language
<QuerySet [<Person: Person object (1)>]>
>>> person_laguage[0]language.values()
<QuerySet [{'id': 1, 'name': 'Korean'}, {'id': 2, 'name': 'English'}]>
prefetch_related()
매개변수로 역참조 되는 Person
의 참조키 language
를 지정
- related_name 변수로 지정시
>>> person_language = Person.objects.prefetch_related('language').filter(id=1)
>>> str(person_language.query)
'SELECT `PERSON`.`id`, `PERSON`.`name`, `PERSON`.`city_id` FROM `PERSON` WHERE `PERSON`.`id` = 1'
>>> str(person_language[0].language.all().query)
'SELECT `LANGUAGE`.`id`, `LANGUAGE`.`name` FROM `LANGUAGE` INNER JOIN `PERSON_LANGUAGE` ON (`LANGUAGE`.`id` = `PERSON_LANGUAGE`.`LANGUAGE_id`) WHERE `PERSON_LANGUAGE`.`PERSON_id` = 1'
prefetch_related()
로 query를 확인 시, 제일먼저 PERSON
테이블 기준으로 쿼리를 실행한다
- 추가로 참조되는 키 기준으로 query를 확인 시, 참조테이블인
LANGUAGE
테이블 기준으로 쿼리를 실행한다.
- 즉, 2번의 쿼리가 실행되는 것을 확인 할 수 있다.