아래와 같은 VIew가 있다고 가정하자. 이 View는 함수형 View로 작성이 되어있다. 이 함수형 View를 클래스형 View로 바꿔보자
from django.shortcuts import get_object_or_404, render,redirect
from django.http import HttpResponseRedirect
from django.urls import reverse
from polls.models import Choice, Question
def index(request):
latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return redirect('polls:results')
각 View의 성격 파악하기
우선 각 View함수의 성격을 파악해 보자
- index : 이 애플리케이션의 index페이지이다. Question 모델의 값에서 마지막 5개의 값을 읽어와서 컨텍스트로 넘긴다
- index함수는 질문 리스트를 보여주는 로직이다. 그렇기 때문에 ListView 클래스 뷰를 사용하면 된다
- detail : question_id로 넘어온 값에 대해서 세부적인 정보를 보여주는 뷰이다. 이는 DetailView로 대체할 수 있다
- results : 질문에 대한 투표 결과를 보여준다.
- vote : 투표를 하고 난 후에 POST로 결과를 처리한다. 만약 선택한 값이 없는 경우에는 예외를 발생시킨다. 반대로 선택한 값이 있는 경우에는 결과창으로(result) redirect를 진행한다.
index 뷰 변환하기
우선 ListView를 상속받아야한다. 그리고 반환하고자 하는 template을 template_name변수를 재정의하여 선언한다.
class IndexView(generic.ListView):
template_name = 'polls/index.html'
이 다음 컨텍스트 이름을 재정의 한다. 컨텍스트 이름을 재정의하기 위해서는 'context_object_name'을 재정의 하면 된다. 예를 들어 'latest_question_list'로 재정의 한다고 가정하면 아래와 같이 작성할 수 있다. 디폴트 컨텍스트 명은, object_list 혹은 get_queryset에서 반환하는 모델의 소문자_list이다(여기서는 question_list가 될 수 있다.).
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
그 다음 처리대상 객체 리스트를 구성하기 위해 get_queryset()메소드를 오버라이딩 해준다. get_queryset메소드는 django/views/generic/list.py 에 정의되어있다.
메소드 document를 보면, View를 반환하는 메소드라고 한다. 반환타입은 iterable이어야 하며, 'QuerySet'의 인스턴스여야한다. QuerySet은 데이터베이스로부터 꺼내온 컬렉션을 의미한다(Django ORM)
여기서는 위 함수형 view와 동일하게 하기 위해서 Question 모델에서 마지막 5개 질문을 반환하는 로직을 가지게끔 get_queryset을 오버라이딩 한다.
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
# 최근 생성된 5개의 질문을 반환한다
return Question.objects.order_by('-pub_date')[:5]
detail 뷰 변환하기
우선 detail view는 특정 primary_key에 해당하는 모델에 대한 세부사항을 보여주는 뷰이다. 이는 클래스 뷰로 바꿔줄때 DetailView를 상속받아주면 된다. DetailView를 상속받는 경우에는 특정 객체 하나를 컨텍스트 변수에 담아서 템플릿 시스템에 넘겨주면 된다. 특정 객체를 테이블에서 Primary Key로 조회해서 가져오는 경우, 테이블명, 모델 클래스명만 model 변수를 재정의해서 지정하면 된다.
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
테이블 조회조건에 사용되는 Primary Key값은 URLconf에서 pk라는 파라미터 이름으로 넘겨받게 되면, 이에 대해 DetailView 제네릭 뷰에서 알아서 처리해준다. 위 코드에서 Question테이블로부터 특정 레코드를 가져와 컨텍스트를 구성하게된다. 컨텍스트 변수명은 디폴트 값을 사용하게 되는데, DetailView의 디폴트 컨텍스트 명은 object 혹은 지정한 모델의 소문자로 기재하는 'question'으로 사용할 수 있다.
# urls.py
path('<int:pk>/',DetailView.as_view(), name='detail'),
이 말을 조금 쉽게 보기 위해서는 코드를 분석해 보면 된다.
위 코드 부분이 DeatilView부분이다. 다중상속으로 되어있는것중 BaseDetailView를 따라 올라가보면
BaseDetailView클래스에 get함수가 정의되어있다. 이는 GET HTTP 메소드가 들어오면 처리하는 함수이다. get_object 메소드를 호출하게 되는데, 이 메소드 document를 보면, 아래와 같이 작성되어있다.
"""
Return the object the view is displaying.
Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
Subclasses can override this to return any object.
"""
라고 되어있다. 보면 self.queryset 그리고 'pk' 혹은 'slug' 중 하나가 필요하다고 되어있다. query_set은 get_queryset()메소드를 통해서 반환받게 된다.
pk같은 경우에는 위에서 봤듯이 URLconf에 정의한것을 볼 수 있다.
results 뷰 변환하기
results view는 투표의 결과를 보여주는 view이다. results 뷰 또한 각 질문에 대한 세부사항을 보여주는 로직이기 때문에 DetailView 클래스를 상속받아 작성한다. 설정 또한 선택한 Question에 대한 결과를 보여주는 로직이기 떄문에, 위에있는 detail 뷰와 동일하게 작성해준다.
class ResultView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
vote 뷰(함수형 뷰로 계속 사용)
def vote(request,question_id):
question = get_object_or_404(Question,pk = question_id)
try:
selected_chocie = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render(request, 'polls/detail.html',{
'question' : question,
'error_message' : "You didn't select a choice"
})
else:
selected_chocie.votes += 1
selected_chocie.save()
return redirect('polls:results')
'Back-End > Python Django' 카테고리의 다른 글
[Django] static 파일 처리하기 (0) | 2022.04.06 |
---|---|
[Django] DEBUG=False 상태에서 static 파일 사용하기 (0) | 2022.04.05 |
[Django] get_context_data() 메소드의 작동원리 (0) | 2022.03.05 |
[Django] apps.py의 간단한 활용 (0) | 2022.03.05 |
[django] 클래스형 뷰 (0) | 2022.03.01 |