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)
참고링크:
안녕하세요.
글 잘 읽었습니다.