장고 튜토리얼을 진행하면서 view를 작성하는 방법이 두 가지 존재한다는 것을 알게됐다. 아직 장고를 이용해서 많은 프로젝트를 진행해보지 않아서 어떤게 좋고 어떤게 나쁘고는 잘 모르겠지만, 확실한 것은 두가지 방법 모두 자세히 알고 있어야 한다는 것이다.
Class-Based Views vs Fuction-Based Views
Github - Django에 들어가보면Veiw.as_view()
구성을 확인할 수 있다.
class View:
@classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
# Code omitted for clarity
# ...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
# Code omitted for clarity
# ...
return view
as_view()
메소드에 의해 리턴되는 view
함수는 dispatch
메소드에 request
를 전달한다. 그러면 dispatch()
메소드는 request
타입(GET, POST 등)에 따른 적합한 메소드를 실행한다.
장고 튜토리얼을 진행하며 작성했던 두 코드를 확인해보자.
Function-based Views
urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
# ex /polls/
path('', views.index, name='index'),
# ex /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex /polls/5/vote/
path('<int:question_id>/vote', views.vote, name='vote'),
]
veiws.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from .models import Question, Choice
def index(request):
latest_question_list = Question.objects.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 HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
Class-based Views
urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
# ex /polls/
path('', views.IndexView.as_view(), name='index'),
# ex /polls/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
# ex /polls/5/results/
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
# ex /polls/5/vote/
path('<int:question_id>/vote', views.vote, name='vote'),
]
veiws.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.views import generic
from .models import Question, Choice
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
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 HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
함수 기반 뷰는 django.veiws.View
클래스를 상속받는 대신, 직접 함수를 작성하여 request를 처리한다. 보통 api_view()로 request 메소드가 무엇인지 명시해주고, 다수의 request 메소드를 사용할 경우 if 조건문으로 구분하여 처리한다.
클래스 기반 뷰는 장고에 제네릭 클래스 기반 뷰라는 강력한 기능이 있다.
제네릭 클래스 기반 뷰는 새로운 객체 생성, 폼 처리, 리스트 뷰, 페이징, 아카이브 뷰 등과 같은 웹 어플리케이션의 일반적인 사용 사례를 해결하기 위해 도입되었다. 이들은 Django 코어에 자리잡아 django.views.generic 모듈에 의해 구현된다. 이 기능은 매우 훌륭하며 개발 프로세스 속도를 높여준다. 사용가능한 뷰들의 목록은 다음과 같다.
Simple Generic Views
- View
- TemplateView
- RedirectView
Detail Views
- DetailView
List Views
- ListView
Editing Views
- FormView
- CreateView
- UpdateView
- DeleteView
Date-Based Views
- ArchiveIndexView
- YearArchiveView
- MonthArchiveView
- WeekArchiveView
- DayArchiveView
- TodayArchiveView
- DateDetailView
Built-in class-based views API
장단점 비교
함수 기반 뷰
-
장점: 구현이 간단함, 읽기 편함, 직관적인 코드, 데코레이터 사용이 간단함
-
단점: 코드를 확장하거나 재사용하기 어려움, 조건문으로 HTTP 메소드 구분
(제네릭) 클래스 기반 뷰
-
장점: 코드를 확장하거나 재사용하기 쉬움, mixin(다중 상속) 같은 객체지향 기술을 사용할 수 있음, 분리된 메소드로 HTTP 메소드 구분, 내장 제네릭 클래스 기반 뷰
-
단점: 읽기 힘듦, 직관적이지 않은 코드, 부모 클래스/mixin에 숨어있는 코드들, 뷰 데코레이터를 사용하려면 따로 import를 하거나 메소드를 오버라이드 해야 함수
참조 :
https://yuda.dev/245
https://www.django-rest-framework.org/tutorial/3-class-based-views/
https://simpleisbetterthancomplex.com/article/2017/03/21/class-based-views-vs-function-based-views.html