CBV
에서 발생하는 각각의 request
마다 새로운 인스턴스를 생성하므로 상태 정보를 인스턴스에 저장하는 것이 스레드 세이프 하다. CBV
는 url pattern
에서 as_view()
클래스 메서드를 통해 배치(deploy
)한다.
# ex)
urlpatterns = [
path('view/', MyView.as_view(size=42)),
]
스레드 세이프 하기위한 view 인자.
view
를 통해 전달하는 인자들은 해당view
의 인스턴스에 모두 공유된다. 이는list
,dictionary
등mutable
한 객체를 이용해서는 절대로 안된다. 만약mutable
한 객체를 이용하여view
를 생성했다면, 한 유저가view
에 접근을 하는 동작으로 그 다음 유저에 영향을 미칠 수 있다.
똑같은 맥락으로, as_view()
를 통해 전달된 인자는 해당 클래스 뷰의 인스턴스에 할당된다. 앞에서 언급했듯이, 이는 해당 클래스 뷰에 대한 모든 요청에서, as_view()
로 할당한 인자에 접근할 수 있다는 뜻이다. 이때, 인자로 받을 변수(위에서 self.size
)는 class attributes
(MyView
의 attributes
)로 이미 존재하고 있어야만 할당 가능하다. (hasattr
메소드로 체크한다.)
기본 View
클래스는 상속을 위한 부모 클래스라고 여겨진다. 해당 클래스만으로는 프로젝트에서 요구하는 다양한 생산성을 제공하지 않을 것이다. 그래서 보통 Mixins를 통해 확장하여 사용할 수 있다.
장고의 generic views
는 믹스인과 base View
를 통하여 데이터의 객체를 쉽게 다룰 수 있게끔 개발되어 있다.(의역:Django's generic views are built off of those base views, and were developed as a shortcut for common usage patterns such as displaying the details of an object) 이는 관용과 추상화와 view
개발에서 찾은 패턴을 종합하여 개발자 입장에서 빠르게 작성하고, 반복코드를 작성하지 않으면서 보편적인 view
를 만들도록 하였다.
대부분의 generic view
는 queryset
에 대한 숙지를 요구하므로 다음의 링크를 통해 익히도록 하자.
다음 소개하는 3가지 기본 클래스는 장고 뷰에서 자장 기본적으로 제공되는 클래스이다. 우리 그저 부모클래스 정도로 생각하겠지만, 우리는 이를 직접 사용할 수 있을 뿐 아니라 상속해서 사용할 수 도 있다. 하지만 프로젝트에서 요구하는 충분한 기능을 제공하지는 못하기 때문에 Mixin
, generic class-based views
를 사용하여 확장할 수 있다.
대부분의 장고 CBV
클래스는 우리가 소개하고 있는 클래스를 상속하거나 믹스인을 상속한다. 상속체인(inheritance chain)이 매우매우매우 중요하기 때문에, 자식 클래스들은 상속의 순서(MRO
)를 명시해야한다. MRO
는 Method Resolution Order
의 약자로 자세한 사항은 검색을 통해 공부하자.(python
개념)
View
django.views
에서 import
할 수 있다. (It isn't strictly a generic view and thus can also be imported from django.views.)# method FlowChart
# 1. setup()
# 2. dispatch()
# 3. http_method_not_allowed()
# 4. options()
예시 views.py
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
예시 urls.py
from django.urls import path
from myapp.views import MyView
urlpatterns = [
path('mine/', MyView.as_view(), name='my-view'),
]
http_method_names
: 해당 view에서 수용 가능한 HTTP method
이름의 집합 (type
: list
)
# Default
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
classmethod as_view
(**initkwargs)
request
를 가지고 있는 callable view
와 response
를 반환한다.
response = MyView.as_view()(request)
반환된 view
는 view_class
와 view_initkwargs
attributes
를 가지고 있다. 요청 / 응답 사이클이 한 호출되는 동안에, setup()
이라는 메서드가 view
에 있는 request
라는 attribute
에 HTTPRequest
를 할당하고, URL pattern
에서 포착한 추가적인 args
와 kwargs
를 각각 받는다. 그 다음 dispatch()
메소드를 호출한다.
setup(request, *args, **kwargs)
dispatch()
실행 전에 호출하는 함수, 만약 오버라이드를 한다면 super()
를 꼭 호출할 것
dispatch(request, *args **kwargs)
:
뷰의 뷰파트이다.(The view
part of the view 무슨말이야...?) request
의 arg
(인자)를 view
의 args
에 추가하고, HTTP response
를 반환하는 메소드 이다.
기본 구현사항은 http method
에서 GET
명령은 get()
메서드에, POST
명령은 post()
메서드에 매칭하는 작업을 한다.
# dispatch() 이해하기
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
as_view()
로 넘어가는 request
의 method
가 self.http_method_names
안에 있는지 없는지를 판단하여, getattr(self, request.method.lower(), self.http_method_not_allowed)
함수로 handler
를 제어한다.
getattr(__o, name, __default)
: 해당 인스턴스에 name
이라는 어트리뷰트가 있으면 name
을 반환하고, 그렇지 않으면 __default
를 반환하라는 함수.예를들어, request의 명령이 GET
으로 들어왔을 경우, handler
는 get
으로 할당되어, as_view()
함수에서 self.dispatch(request, *args **kwargs)
부분에서 self.get(request, *args **kwargs)
메서드로 치환되는 효과를 가지게 된다.
다른 method 형태로 들어와도(POST
, DELETE
, PATCH
, PUT
등), dispatch를 통해 각각 post(), delete(). patch(), put() 메소드로 치환되어 우리가 만든 views.py의 해당 메서드를 호출하는 효과를 가지게 된다.
뿐만 아니라, self.http_method_names
에 request.method
가 없을경우, 1차로 if
문에서 , 2차로 getattr
내장메서드로 self.http_method_not_allowed
메서드를 호출하면서 http method
를 제어할 수 있게 된다.
함수형 프로그래밍방식을 모른다면 이해하기 까다로운 코드였다...
`http_method_not_allowed(*request*, **args*, ***kwargs*)
view
가 지원하지 않는 HTTP method
로 호출된다면, 해당 메서드를 호출한다. HttpResponseNotAllowed
라는 객체를 반환하고, 이는 해당 view class
가 지원하는 method
리스트를 텍스트로 반환한다.
options(request, *args, **kwargs
)
OPTIONS HTTP
에 대한 request
를 처리하는 함수입니다. response
에 self._allowed_methods()
를 Allow
헤더에 담아 반환합니다.
TemplateView
django.views.generic.base.TemplateView
주어진 템플릿을 랜더하는 클래스. URL parameters
를 통해 받아온 인자를 포함한 context
를 가진다.
django.views.generic.base.TemplateResponseMixin
django.views.generic.base.ContextMixin
django.views.generic.base.View
urls.py
에서 path(My_class.as_view())
실행
as_view()
에서 받은 initkwargs
(예: My_Class.as_view(extra_context={"foo":"bar})
) http method
가 있는지 검사, 그리고 My_Class
에 extra_context
라는 attribute
가 있는지 검사. 모두 문제가 없다면, setup()
, dispatch()
메소드를 실행(위의 View
클래스에서 설명한 과정을 했으므로 생략)
as_view()
에서 반환된 객체는 request.method
에 따라, get()
, post()
등의 메소드를 호출하는 결과와 같다. 이때, TemplateView
는 get()
메소드 밖에 없으므로 get()
메소드를 호출한다.
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
ContextMixin
에서 상속한 get_context_data
메소드를 실행하여, render
에 필요한context
를 정제한다.
TemplateResponseMixin
에서 상속한 render_to_response(context)
메소드를 실행하여, Response
인스턴스를 반환한다.
RedirectView
(미번역 나중에 완성예정)class django.views.generic.base.RedirectView
주어진 URL
로 리다이렉트 하는 뷰