Base Views

SINHOLEE·2020년 8월 31일
0

django CBV DOCS(번역)

목록 보기
1/1

명세(Specification)

CBV에서 발생하는 각각의 request마다 새로운 인스턴스를 생성하므로 상태 정보를 인스턴스에 저장하는 것이 스레드 세이프 하다. CBVurl pattern에서 as_view() 클래스 메서드를 통해 배치(deploy)한다.

# ex)
urlpatterns = [
    path('view/', MyView.as_view(size=42)),
]

스레드 세이프 하기위한 view 인자.

view를 통해 전달하는 인자들은 해당 view의 인스턴스에 모두 공유된다. 이는 list, dictionarymutable한 객체를 이용해서는 절대로 안된다. 만약 mutable한 객체를 이용하여 view를 생성했다면, 한 유저가 view에 접근을 하는 동작으로 그 다음 유저에 영향을 미칠 수 있다.

똑같은 맥락으로, as_view()를 통해 전달된 인자는 해당 클래스 뷰의 인스턴스에 할당된다. 앞에서 언급했듯이, 이는 해당 클래스 뷰에 대한 모든 요청에서, as_view()로 할당한 인자에 접근할 수 있다는 뜻이다. 이때, 인자로 받을 변수(위에서 self.size)는 class attributes(MyViewattributes)로 이미 존재하고 있어야만 할당 가능하다. (hasattr 메소드로 체크한다.)

Base VS Generic Views

기본 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 viewqueryset에 대한 숙지를 요구하므로 다음의 링크를 통해 익히도록 하자.

Base Views

다음 소개하는 3가지 기본 클래스는 장고 뷰에서 자장 기본적으로 제공되는 클래스이다. 우리 그저 부모클래스 정도로 생각하겠지만, 우리는 이를 직접 사용할 수 있을 뿐 아니라 상속해서 사용할 수 도 있다. 하지만 프로젝트에서 요구하는 충분한 기능을 제공하지는 못하기 때문에 Mixin, generic class-based views를 사용하여 확장할 수 있다.

대부분의 장고 CBV클래스는 우리가 소개하고 있는 클래스를 상속하거나 믹스인을 상속한다. 상속체인(inheritance chain)이 매우매우매우 중요하기 때문에, 자식 클래스들은 상속의 순서(MRO)를 명시해야한다. MROMethod 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'),
    ]
    

attributes

  • http_method_names : 해당 view에서 수용 가능한 HTTP method 이름의 집합 (type: list)

    # Default
    ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

Methods

  • classmethod as_view(**initkwargs)

    request를 가지고 있는 callable viewresponse 를 반환한다.

    response = MyView.as_view()(request)

    반환된 viewview_classview_initkwargs attributes를 가지고 있다. 요청 / 응답 사이클이 한 호출되는 동안에, setup()이라는 메서드가 view 에 있는 request라는 attributeHTTPRequest를 할당하고, URL pattern에서 포착한 추가적인 argskwargs를 각각 받는다. 그 다음 dispatch() 메소드를 호출한다.

  • setup(request, *args, **kwargs)

    dispatch() 실행 전에 호출하는 함수, 만약 오버라이드를 한다면 super()를 꼭 호출할 것

  • dispatch(request, *args **kwargs):

    뷰의 뷰파트이다.(The view part of the view 무슨말이야...?) requestarg(인자)를 viewargs에 추가하고, 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()로 넘어가는 requestmethodself.http_method_names 안에 있는지 없는지를 판단하여, getattr(self, request.method.lower(), self.http_method_not_allowed)함수로 handler를 제어한다.

      • getattr(__o, name, __default) : 해당 인스턴스에 name이라는 어트리뷰트가 있으면 name을 반환하고, 그렇지 않으면 __default를 반환하라는 함수.
    • 예를들어, request의 명령이 GET으로 들어왔을 경우, handlerget으로 할당되어, 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_namesrequest.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를 처리하는 함수입니다. responseself._allowed_methods()Allow 헤더에 담아 반환합니다.

TemplateView

class django.views.generic.base.TemplateView

주어진 템플릿을 랜더하는 클래스. URL parameters를 통해 받아온 인자를 포함한 context를 가진다.

조상 클래스(MRO)
  • django.views.generic.base.TemplateResponseMixin
  • django.views.generic.base.ContextMixin
  • django.views.generic.base.View
메소드 흐름
  1. urls.py 에서 path(My_class.as_view()) 실행

  2. as_view()에서 받은 initkwargs(예: My_Class.as_view(extra_context={"foo":"bar})) http method 가 있는지 검사, 그리고 My_Classextra_context라는 attribute가 있는지 검사. 모두 문제가 없다면, setup(), dispatch() 메소드를 실행(위의 View 클래스에서 설명한 과정을 했으므로 생략)

  3. as_view()에서 반환된 객체는 request.method에 따라, get(), post() 등의 메소드를 호출하는 결과와 같다. 이때, TemplateViewget() 메소드 밖에 없으므로 get()메소드를 호출한다.

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)
  4. ContextMixin에서 상속한 get_context_data메소드를 실행하여, render에 필요한context를 정제한다.

  5. TemplateResponseMixin에서 상속한 render_to_response(context) 메소드를 실행하여, Response 인스턴스를 반환한다.

RedirectView(미번역 나중에 완성예정)

class django.views.generic.base.RedirectView

주어진 URL로 리다이렉트 하는 뷰

profile
엔지니어로 거듭나기

0개의 댓글