장고 INNER JOIN 을 거는 법!!!
아래의 테이블 모델을 살펴보자.
class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published')
class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices') choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
- Question 과 Choice 라는 2개의 모델 (테이블) 을 만들었다
- Choice 에 question 이라는 ForeignKey가 걸린 것이 보일것이다. 이것은 Choice 모델의 테이블에 "question_id" 라는 필드를 만들게 되고, 모델 설계 상, Question : Choice = 1 : N 의 구조를 낳게 된다.
- related_name 이 choices 인 것에 주목하자. 이것은 Question model 입장에서 Choice model 을 어떤식으로 명명할지에 대한 값이다.
===========================================================================================
조인은 데이터를 SELECT 할때, 기준이되는 모델에 따라 거는 방향이 다른데
아래와같이 2가지 종류가 있다.
1. Many-to-one : Choice 모델을 기준으로 Question 데이터를 불러올 경우.
요건 참 쉽다. 일단 참고할만한 원문 Documentation 내용 링크는 아래와 같다.
choice_data_with_question = Choice.objects.select_related('question')
- 위와같이
2. One-to-many : Question 모델을 기준으로 Choice 데이터를 불러올 경우
이게 좀 문젠데, 일단 Documentation 내용은 아래와 같다.
크게 2가지 방법이 있는데, 하나씩 설명하도록 하겠다.
첫번째 방법 : prefetch_related() 사용하기
>>
이것은 Question 모델이 Choice 에서 지정한 related_name 인 choices 라는 Attribute 로
Choice 모델의 Default Manager를 연동시켜 놓는 것을 말한다. 말이 좀 어려운데, 쉽게 말하면
question_list 의 각 element 인 question 에 question.choices =
Choices.objects 가 붙어있는 상태를 만드는 일이라고나 할까...? 그리고 이것은 실직적으로 아직 쿼리를 실행시키는
함수가 call 되지 않은 상태이기 때문에
<View 쪽>
def get_context_data():
context["questions"] = Question.objects.prefetch_related('choices')
return context
<Template 쪽>
{% for question in questions %}
<b>{{ question.question_text }}</b>
<ul>
{% for choice in question.choices.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
{% endfor %}
※ Choice 모델에서 related_name 을 지정하지 않았을 경우에는 템플릿 쪽에서 question.choice_set.all 을 사용하면 된다.
두번째 방법 : annotate() 사용하기
def get_context_data():
question_data_with_choices
= Question.objects.annotate(choice_id=F('choices__id'),
choice_text=F('choices__choice_text'),
votes=F('choices__votes')).annotate(Count('id))
=============================================================================================
- Many to one 은 select_related() 를 잘 사용하면 된다
- One to many 는 prefetch_related() 혹은 annotate() 를 잘 사용하면 된다,
댓글
댓글 쓰기