본문 바로가기

web/Django

How Django process a request

https://www.b-list.org/weblog/2006/jun/13/how-django-processes-request/

의 글을 번역한 글입니다. 해당 글은 2006년에 쓰여진 글로 현재 django 버전과 다를 수 있습니다.

  1. 들어온다!!
  2. 핸들러가 있어
  3. 그린라이트! 이제부터 시작.
  4. 미들웨어 1 라운드
  5. 해결할 시간
  6. 미들웨어 2라운드
  7. Into the view
  8. 템플릿
  9. django의 템플릿 구조
  10. 응답시간(Response time)
  11. 미들웨어 처리 3 예외
  12. 아직도 응답하지 않았어?
  13. 미들웨어 처리 4: 마지막 단계
  14. 응답

1. 들어온다!!

2가지 방법으로 장고 서버를 호출한다.

  1. 아파치/모드파이선(apache/mod_python) 서버가 셋업되어있을 경우, 모드 파이선이 리퀘스트를 장고에게 전달하고 django.core.hanlders.modpython.ModPythonHandler 인스턴스를 생성한다.
  2. WSGI를 준수하는 다른 요소일 경우 장고 django.core.handlers.wsgi.WsgiHandler 인스턴스를 생성한다.

두 클래스 모두 django.core.handlers.base.BaseHandler 에서 상속되며 모든 유형의 요청에 필요한 공통 코드를 포함합니다.

2. handle이 있어

handler가 인스턴스화 되면, 다음과 같은 과정을 거친다.

  1. handler는 Django 설정 파일을 가져옵니다.
  2. handler는 Django의 사용자 정의 예외 클래스를 가져옵니다.
  3. handler는 자체 load_middleware(MIDDLEWARE_CLASSES) 메서드를 호출 하여 설정에 나열된 모든 클래스를 로드 하고 검사합니다.

미들웨어 클래스는 request, view, response 및 except 네 가지 처리 단계에 연결할 수 있습니다. 그것은 각각 process_request, process_view, process_response와 process_exception 의 함수로 정의되어 호출 됩니다.

handler가 미들웨어를 호출 할 때 해당 이름의 가진 메소드 4 개의 목록을 작성합니다.

  1. _request_middleware -> process_request
  2. 메서드를 정의한 미들웨어 클래스의 메서드 목록입니다 (각 경우에 실제 메서드가되므로 직접 호출 할 수 있음).
  3. _view_middlewareprocess_view
  4. 정의한 미들웨어 클래스 의 메소드 목록입니다 .
  5. _response_middlewareprocess_response
  6. 정의한 미들웨어 클래스 의 메소드 목록입니다 .
  7. _exception_middlewareprocess_exception
  8. 정의한 미들웨어 클래스 의 메소드 목록입니다 .

3. 그린라이트! 이제부터 시작.

이제 핸들러는 request의 처리를 시작할 준비가 되었으므로 request_started 를 디스패킹 합니다. 그런 다음 django.http.HttpRequest 의 하위 클래스를 인스턴스화합니다.

HttpRequest 는 get_response 를 호출하고,  HttpRequest 유일한 파라미터로 전달합니다.

4. 미들웨어. 1 라운드

첫 번째 작업은  get_response 의 _request_middleware인스턴스 변수를 반복하고 해당 목록의 각 메서드를 호출하여 HttpRequest인스턴스를 인수로 전달하는 것입니다 . 반복 실행 중 하나가 반환을 한다면 메인 핸들러 코드로 돌아갑니다. get_response 다른 미들웨어 클래스가 무엇을하고자하는지 기다릴 필요도 없습니다. 그냥 돌아오고 핸들러는 응답 단계로 들어갑니다.

그러나 더 일반적으로 여기에 적용된 미들웨어 메서드는 단순히 일부 처리를 수행하고 요청의 속성을 추가, 제거 또는 보완할지 여부를 결정합니다.

5. 해결할 시간

미들웨어중 어느것도 리스폰스를 반환하지 않았다면, 핸들러는 요청된 URL를 확인합니다. 핸들러는 세팅 파일에 있는 ROOT_URLCONF 를 읽고, django.core.urlresolvers.RegexURLResolver 인스턴스를 생성한 다음해당 인스턴스의 resolve 메소드를 호출한다.

URL은 매우 간단한 패턴을 따른다. 설정에 지정된 URL 구성 파일에 urlpatterns의해 생성 된 목록의 각 항목에 대해 요청 된 URL 경로가 해당 항목의 정규식과 일치 하는지 확인합니다 .

앞써 설정된 ROOT_URLCONF에는 두가지 옵션이 있습니다.

  1. 항목에 포함된 호출(하위 경로)이있는 경우 해결 프로그램 은 일치 하는 URL 비트를 잘라 내고 포함에 지정된 URL 구성 파일로 이동하여 urlpatterns목록 의 항목에 대해 반복을 시작합니다. URL 계층 구조의 깊이와 모듈성에 따라 작업은 여러 번 반복 될 수 있습니다.
  2. 그렇지 않다면 3가지를 리턴합니다.
    1. URL 일치로 지정된보기 함수
    2. URL에서 이름이 지정되지 않은 일치 그룹 목록
    3. URLConf 에서 조합된 키워드 사전

이는 뷰를 지정하는 첫 번째 일치에서 중지되므로, 잘못된 URL 정규식일 경우 잘못된 뷰 기능을 반환합니다.

만약 매칭되는 url 이 없다면 django.core.urlresolvers.Resolver404 예외를 발생시킨다.

6. 미들웨어 2 라운드

뷰 함수가 사용된다면 핸들러가 _view_middleware 리스트에 있는 메소드르 호출해 HttpRequest 를 전달한다. 이 단계에서도 미들웨어가 개입해 핸들러가 리스폰스를 바로 반환하도록 할 수 있다.

7. Into the view

이 시점에서 처리가 진행 중이면 핸들러는 뷰 함수를 호출합니다.

  • 호출가능해야한다.
  • 첫번쨰 인자로 django.http.HttpRequest 의 인스턴스를 받는다.
  • django.http.HttpResponse 인스턴스를 반환하거나 예외를 발생시킨다.

가장 일반적으로 뷰는 Django의 데이터베이스 API를 사용하여 데이터베이스에서 무언가를 생성, 검색, 업데이트 또는 삭제하고 템플릿을 로드하고 렌더링하여 최종 사용자에게 표시합니다.

8. 템플릿

Django의 템플릿 시스템은 두 가지 측면으로 구성되어 있습니다. HTML에는 몇 가지 추가 항목이 포함되어 있으며 대부분 디자이너가 사용하고 있으며, 한 부분은 순수한 파이썬이며 프로그래머가 사용합니다.

HTML 관점에서 Django의 템플릿 시스템은 매우 간단합니다. 알아야 할 세 가지 구조는 다음과 같습니다.

  1. 변수 참조. 템플릿에서 다음과 같이 보입니다 : {{ foo }}
  2. 템플릿 필터.일반적으로 출력 형식 지정에 사용됩니다 (예 : Textile 실행, 날짜 형식 지정 등).
  3. 1번에서 필터를 사용하면 다음과 같습니다  bar{{ foo|bar }}
  4. 템플릿 태그.  {% baz %} {% if foo %} {% for bar in foo %}
  5. 템플릿의 "논리"가 구현되는 경우 사용합니다.

변수 참조는 매우 간단한 방식으로 작동합니다.  와 같이 변수를 직접 인쇄하는 경우 템플릿 시스템 이 변수를 출력합니다. 여기서 유일한 복잡성은 다음과 같은 작업을 할 때입니다 {{ foo.bar }}. 이 경우 템플릿 시스템은 몇 가지 작업을 순서대로 시도합니다.

변수 참조는 매우 간단한 방식으로 작동합니다. {{ foo }} 에서와 같이 변수를 직접 인쇄하는 경우에는 템플릿 시스템에서 변수를 출력하기만 하면 됩니다. 여기서 복잡한 것은 {{ foo.bar }} 와 같은 작업을 수행할 때뿐입니다. 이 경우 템플릿 시스템은 몇 가지 작업을 순서대로 시도합니다.

  1. 먼저 사전 형식의 검색을 통해  foo[‘bar’]가 있는지 확인합니다. 그러면 해당 값이 출력되고 프로세스 종료됩니다.
  2. 사전 조회가 실패하면 다음으로 템플릿 시스템이 속성 조회를 시도하여 foo.bar
  3. 존재 하는지 확인 합니다.  속성이 호출 가능한지 확인하고이 경우 호출을 시도합니다.
  4. 속성 조회가 실패하면 템플릿 시스템은이를 목록 인덱스로 조회합니다.

이 모든 것이 실패하면 템플릿 시스템은 설정 값 TEMPLATE_STRING_IF_INVALID을 출력합니다. 기본값은 빈 문자열입니다.

템플릿 필터는 값과 인수를 받아들이고 새 값을 반환하는 단순한 Python 함수입니다. 예를 들어, date필터는 Python datetime객체를 값으로, 표준 strftime형식화 문자열을 인수로 취하고 해당 형식화 문자열을 해당 datetime객체 에 적용한 결과를 반환합니다.

9. Django 템플릿 구조

내부적으로 Django 템플릿은 'nodes'의 모음으로 표현되며, 이것들은 django.template.Node에서 상속되는 파이썬 클래스이다. 노드들은 다양한 종류의 처리를 할 수 있지만, 하나의 공통점을 가지고 있다: 모든 노드들은 django.template의 두 번째 인수(물론 첫 번째 인수가 노드 인스턴스가 될 것이다)로 받아들이는 렌더라는 메소드를 가져야 한다. django.template.Context에 액세스할 수 있는 모든 변수를 포함하는 dict과 유사한 개체입니다. nodes의 렌더 방법은 문자열을 반환해야 하지만 nodex가 출력 이외의 작업을 수행하려는 경우(예: 전달된 컨텍스트 인스턴스에서 변수를 추가, 제거 또는 수정하여 템플릿 컨텍스트를 수정하려는 경우) 빈 문자열을 반환할 수 있습니다.

Django에는 유용한 기능을 제공하는 노드의 여러 하위 클래스가 포함되어 있습니다. 예를 들어, 기본 내장 템플릿 태그는 각각은 노드의 하위 클래스(예: IfNode를 구현하는 IfNode, 태그용 태그를 구현하는 ForNode 등)에 의해 처리됩니다. 기본 제공 태그는 모두 django.template.default 태그에 있습니다. 실제로 위에서 설명한 모든 템플릿 구조는 어떤 종류의 노드이며, 일반 텍스트도 마찬가지이다. 변수 룩업은 가변 노드에 의해 처리되고 필터는 가변 노드에 적용되며 태그는 다양한 유형의 노드이고 일반 텍스트는 텍스트 노드이다.

일반적으로 보기는 다음 단계를 순서대로 수행하여 템플릿을 렌더링합니다.

  1. 렌더링 할 템플릿을로드합니다.django.template.loader.get_template의 인스턴스를 반환 합니다.
  2. 원하는 템플릿 파일을 찾기 위해 구문 분석 된 템플릿과 이를 사용하기위한 메서드를 포함하는 객체 인
  3. Context 템플릿을 렌더링하는 데 사용할  인스턴스를 생성합니다.
  4. 개체를 첫 번째 위치 인수로 사용 하여 TemplaterenderContext 인스턴스의 메서드를 호출합니다

10**. 응답시간(Response time)**

템플릿이 렌더링되거나 다른 종류의 적절한 출력이 생성되면 뷰는의 인스턴스를 생성합니다 django.http.HttpResponse 클래스의 생성자는 두 가지 인수를 사용합니다.

  • 응답 리스폰스 바디에 담을 스트링
  • Content-Type 헤더 값, 기본값은 DEFAULT_MIME_TYPE="text/html", DEFAULT_CHARSET="utf-8"입니다.

11**. 미들웨어 처리 3 예외**

뷰에서 예외가 발생하면 get_response가 _exception_middleware에 있는 메소드를 호출해 HttpRequest 와 예외를 인자로 전달한다. 호출된 메소드 중 하나가 HttpResponse를 반환한다.

12. 아직 응답하지 않았어?

이 시점에서 HttpResponse가 여전히 없을 수 있습니다. 이는 다음과 같은 여러 요인 때문일 수 있습니다.

  1. 뷰가 값을 반환하지 않음
  2. 뷰가 예외를 발생시키지만 그걸 처리할수 있는 미들웨어가 없음
  3. 예외를 처리하는 미들웨어에서 새 예외사항이 발생함

이러한 상황이 발생할 경우 get_response 가 자체적으로 에러를 처리합니다.

  1. DEBUG=True 이고 익셉션은 http404 일 경우, get_response가 django.views.debug.technical_404_response 를 실행합니다.  HttpRequest 와 익셉션 정보를 전달한다. 이 뷰는 URL Resolver 가 매치하려고 햇었던 패턴에 대한 정보를 표시한다.
  2. 만약 DEBUG=False 이고 익셉션은 Http404일 경우 get_response 가 URL Resolver 의 resolve_404 를 호출한다. 이 메소드는 url 설정을 읽어서 어떤 뷰가 404 에러를 핸들링 해야 하는지 찾는다. 디폴트 값은 django.views.defaults.page_not_found 이지만, 변수 hanlder404에 값을 할당해 URL 설정을 오버라이드 할 수 있다.
  3. 익셉션의 종류에 상관없이, DEBUG=True 일 경우, get_response가 django.views.debug.technical_500_response 뷰를 실행하고 HttpResponse와 익셉션을 인자로 전달한다. 이 뷰는 트레이스백, 스택 각 레벨의 지역 변수, 등 자세한 정보를 제공한다.
  4. DEBUG=False 일 경우, get_response 가  resolve_500 메소드를 호출하고, 3번과 비슷한 방법으로 작동한다.

추가적으로, django.http.Http404 , python 내장 함수인  SystemExit 이외의 익셉션일 경우, 핸들러는 디스패처 신호 got_request_exception을 실행하고 반환하기 전에 장고 admins 설정에 리스팅된 사람들에게 메일을 발송합니다.

13. 미들웨어 최종 라운드

이 시점에서는 get_response의 모든 수준에서 잘못된 것이 무엇이든 상관없이 HttpResponse 인스턴스를 반환해야 합니다. HttpResponse가 _response_middleware 인스턴스 변수를 루프하고 거기서 찾은 메소드를 적용하여 HttpRequest와 HttpResponse를 인수로 전달한다.

미들웨어가 동작하는 마지막 단계입니다.

14. 응답

이제 마무리 할 시간이에요. 미들웨어의 최종 라운드가 적용되면, 핸들러는 디스패처 시그널 request_finished를 전송하는데, 이는 현재 요청 중에 실행하고자 하는 모든 것에 대한 마지막 호출이다. 이 신호를 수신하는 처리기는 사용 중인 모든 리소스를 정리하고 해제해야 합니다. 예를 들어 Django는 열려 있는 데이터베이스 연결을 닫는 request_finish에 수신기를 연결합니다.

그런 다음, 처리기는 인스턴스화된 모든 응답(현재, 처리기에 따라 mod_python 적절한 응답 또는 WSGI 호환 응답)으로 다시 전송하기 위해 적절한 반환 값을 생성하고 반환합니다.

휴우...

드디어 끝났습니다. 이것이 처음부터 끝까지 Django가 요청을 처리하는 방식입니다.