The only reason to use either of these methods is when a single large query is preferable to many small queries. Django uses the large query to create models in memory preemptively rather than performing on demand queries against the database.
select_related :You can use related_name in the linking model for backward reference.
We use select_related when the object that you're going to select is a single object, which means forward ForeignKey, OneToOne and backward OneToOne.
select_related는 각각의 lookup마다 SQL의JOIN을 실행하여 테이블의 일부를 가져오고, select .. from에서 관련된 필드들을 가져온다.
select_related works by creating an SQL join and including the fields of the related object in the SELECT statement. For this reason, select_related gets the related objects in the same database query.
..select_related does an SQL join and therefore gets the results back as part of the table from the SQL server.
selected_related를 사용했을 때와 사용하지 않았을 때의 query 방식에 대해서 살펴보자.다음 모델의 관계는 child인Drink가 SubCategory 와 Category를 parents 로 가지는 역참조관계이며, 하나의 Drink는 하나의 SubCategory 와 Category를 가지는 many-to-one의 관계이다.
🎯 는 데이터베이스를 히트할때를 의미한다.

@ manage.py shell
>>> from drink.models import *
# select_related를 사용하지 않은 경우
>>> drink = Drink.objects.get(id=1) 🎯 [1]
>>> drink
<Drink: dolce cold brew>
>>> SubCategory.objects.filter(id=drink.sub_category_id) [2]
<QuerySet [<SubCategory: cold brew>]>
>>> SubCategory.objects.filter(id=drink.sub_category_id)[0] 🎯 [3]
<SubCategory: cold brew>
>>> SubCategory.objects.filter(id=drink1.sub_category_id)[0].name 🎯 [4]
'cold brew'
# selected_related를 사용한 경우
>>> drink_sr = Drink.objects.select_related('sub_category').get(id=1) 🎯 [a]
>>> drink_sr
<Drink: dolce cold brew>
>>> drink_sr.sub_category.name [b]
'cold brew'
[1]: drink변수에 id=2인 Drink객체를 지정한다.
[2]: 리턴하고 싶은 object를 머릿말에 지정한다. 이 경우는 SubCategory중에서, drink객체가 가진 sub_category_id만을 필터하여 그 쿼리셋을 리턴한다.
[3]: [2]의 결과과 쿼리셋이었으므로, 객체에 접근하기 위해 [ ]를 사용하여 인덱스를 지정한다.
[4]: 객체가 되었으므로, dot notation을 사용하여 name을 구한다.
[a]: select_related를 사용하여, Drink의 필드인 sub_category를 통해, SubCategory에 바로 접근하며, 동시에 get으로 id=1인 Drink를 가져온다.
[b]: 객체이므로, 곧바로 dot notation을 사용하여 SubCategory의 name을 구한다.
We use prefetch_related when we’re going to get a set of things.
That means forward ManyToMany and backward ManyToMany, ForeignKey.
selected_related와 달리, prefetch_related는 SQL의 JOIN을 실행하지 않고, python에서 joining을 실행한다.
prefetch_related does a separate lookup for each relationship, and performs the “joining” in Python.
It is different from select_related, the prefetch_related made the JOIN using Python rather than in the database.
첫번째 모델에서 쿼리를 실행하면서, prefetch에 필요한 모든 IDs를 수집하고, SQL의 WHERE IN(IDs)의 쿼리를 실행한다.
SELECT "credential"."id",
"credential"."uuid",
"credential"."identity_id"
FROM "credential"
WHERE "credential"."identity_id" IN
(84706, 48746, 871441, 84713, 76492, 84621, 51472);
(SQL WHERE IN: https://www.dofactory.com/sql/where-in)
Rather than performing a single join with potentially too many rows, each table is split into a separate query.
class Profile(models.Model):
group = models.ForeignKey(Group, related_name='profiles')
# Now, you can access the foreign key as follows:
group.profiles.all()
(Source: https://stackoverflow.com/questions/17328910/django-what-is-reverse-relationship)
>>> drink2 = SubCategory.objects.filter(id=1).prefetch_related("drink_set") [1]
<QuerySet [<SubCategory: cold brew>]>
>>> drink2[0] [2]
<SubCategory: cold brew>
>>> drink2[0].drink_set.filter(id=1) [3]
<QuerySet [<Drink: dolce cold brew>]>
>>> drink2[0].drink_set.get(id=1).name_en [4]
'dolce cold brew'
[1]. SubCategory중에서 id=1인 SubCategory의 drink_set을 불러오면 해당 id를 가진 Drink들이 쿼리셋으로 리턴된다.
[2]. [ ]를 사용하여, 0번째 인덱스를 불러오면, 하나의 객체로 리턴된다.
[3]. 객체에 다시 필터를 적용하여, id=1인 Drink를 가져온다.
[4]. Drink의 필드인 name_en에도 접근이 가능하다.
A parent(mother) can have many children.
A child can have only one parent(mother).
ForeignKey는 child에 지정하는것이 좋다.
many-to-many관계에서 ForeignKey는 lower level에 지정하는 것이 좋다.
예) class Movie and class Character. One movie can have many characters and many characters can be in one movie. In such case, Character should have a FK.
ForeignKey를 가진 child는 lookup(__)을 사용하여, parent의 필드를 참조할 수 있다.
>>> Drink.objects.filter(sub_category__name='cold brew')
<QuerySet [<Drink: dolce cold brew>, <Drink: cold brew>]>
>>> SubCategory.objects.filter(drink__calories__gt=300)
<QuerySet [<SubCategory: cold brew>, <SubCategory: cold brew>]>
class ModelA(models.Model):
pass
class ModelB(models.Model):
a = ForeignKey(ModelA)
ModelB.objects.select_related('a').all() # Forward ForeignKey relationship
ModelA.objects.prefetch_related('modelb_set').all() # Reverse ForeignKey relationship
(Code, Explanation: https://stackoverflow.com/questions/31237042/whats-the-difference-between-select-related-and-prefetch-related-in-django-orm)
참고링크:
안녕하세요.
글 잘 읽었습니다.