[Django]Django의 동작

Jay·2024년 2월 29일
1
post-thumbnail
post-custom-banner

개요

Django를 사용하여 개발을 시작한 초기에는 구현하는 기능이나 사용하는 리소스들이 제한적이었습니다. 하지만 점차 구현할 기능들도 다양해지고, 이를 구현하기 위해 Django의 구조와 동작을 공부하며 새롭게 배우게 되며 Django라는 프레임워크를 바라보는 시각 또한 많이 달라진 것 같습니다. 이러한 경험을 바탕으로 Django의 구조와 동작 방식 등을 되짚어보고 Django를 사용하여 개발을 하시는 분들에게 저의 관점이나 배운 것들을 공유하고자 조금이나마 제가 아는 부분을 정리해보고자합니다.



Django의 동작

Django로 개발을 공부중이신 분들이라면 아래의 그림을 알아두는 것이 좋을것 같습니다. 아래의 그림은 Django가 어떻게 클라이언트로부터 받은 Request를 처리하고, Response를 반환하는지 간략하게 추상화해놓은 그림입니다.

WSGI

Django는 사용자의 요청을 처리하고 응답을 전송하기 위해 HTTP 프로토콜을 기본으로 사용합니다. WSGI는 웹서버와 웹프레임워크를 연결하기 위한 도구입니다. 서버는 Django 애플리케이션을 실행하면서 콜백 함수를 애플리케이션에게 전달합니다. Django 애플리케이션은 서버로 전달받은 요청을 처리한 후, 콜백함수를 통해 응답을 반환합니다. 즉, WSGINginx, Apache와 같은 웹서버와 Django 애플리케이션의 인터페이스 역할을 수행하게 됩니다.

Django 애플리케이션의 실행

  • settings.py 파일과 django의 예외 클래스들을 임포트합니다.
  • settings.py에 정의된 middleware 클래스들을 찾아 로드합니다.
  • 요청을 처리하고 응답을 반환하기 위한 메소드들의 리스트를 생성합니다. (request, view, response, exception를 다루는 4가지 리스트)
  • request method에 따라서 순회하며 순서대로 함수들을 실행합니다.
  • view 함수를 실행합니다.
  • 예외가 발생하면 예외처리 함수를 실행합니다.

Middleware

WSGI 를 통해 전달된 requestMiddleware 로 전달되게 됩니다. 각 middleware 에는 요청, 응답, view, 예외를 처리하는 4가지 메소드중 1개 이상이 정의되어있습니다. 각 미들웨어에 정의된 해당 메소드들은 settings.py 에 정의된 순서나 역순으로 실행되며, django는 기본적으로 몇가지 미들웨어들을 제공하게 됩니다. WSGI 를 통해 전달받은 requestmiddleware를 통해 url dispatcher/url router, view로 전달된 후 view에서 반환되는 응답이 다시 middleware를 통해 WSGI 로 전달되게 됩니다.

URL Resolution

URL Router는 미들웨어를 통해 전달받은 request에서 url path 정보를 통해 알맞는 view 로 전달하는 역할을 합니다. url pattern에는 정규 표현식이 사용될 수 있으며, Django 에 정의된 url 패턴과 매칭되는 view는 인자로서 request 를 전달받게 됩니다.

Business Logic Layer

view는 라우터를 통해 요청을 전달받게 됩니다. 이 레이어를 비즈니스 로직 레이어라고 부르며, 아마Django를 입문하시는 분들은 개발 시간의 대부분을 이부분에 할애할것입니다. 개발자들은 이 레이어에서 서비스가 제공하는 비즈니스 로직을 구현하게 되며, html template, json과 같은 다양한 응답을 생성하여 반환하게 됩니다.
반환된 응답 혹은 발생한 예외는 다시 middlewareprocess_response 메소드나 process_exception 메소드를 거쳐 WSGI로 전달되게 됩니다. 응답 미들웨어에서는 request를 처리하고 최종적으로 클라이언트에게 전달하기 전에 헤더나 데이터 정보를 추가하거나 수정하게 됩니다.



Middlewares

Middleware Methods

위에서 request가 middleware, view, 다시 middleware 를 통해 응답으로 반환되는 과정에서 각 단계에 원하는 미들웨어를 구현하기 위해서는 구현해야하는 메소드드들이 존재합니다. 즉, 원하는 기능의 미들웨어를 원하는 단계에 구현하기 위해서는 각 단계에 맞는 메소드를 구현해야하고, 구현된 middleware메소드는 WSGI 핸들러에 의해 수집되어 등록된 순서되로 실행되게 됩니다.

  • viewrequest를 전달하기 전에 request를 처리 : process_request()
  • view가 실행되기 전 : process_view()
  • view에서 반환된 request, response 처리 : process_response()
  • view에서 발생한 exception 처리 : process_exception()

미들웨어를 구현하기 위해서는 위의 4가지 메소드들 중 1가지 이상을 구현해야합니다. 각각의 메소드들은 WSGI 핸들러에의해 수집되어 리스트에 등록되며, 등록된 순서 혹은 역순대로 호출됩니다.

process_request(request)

viewrequest를 전달하기 전에 request 객체를 처리할 메소드입니다. settings.pyMIDDLEWARES에 정의된 미들웨어의 process_reqeust() 메소드들을 정의된 순서대로 등록, 호출하여 request 객체를 처리하여 최종적으로 view 함수의 인자로 전달되게 됩니다.

process_request 메소드는 None 혹은 HttpResponse 객체를 반환할 수 있습니다. None을 반환하게 되는 경우 WSGI Handler에 등록된 process_request들을 계속해서 정상적으로 실행하여 viewrequest를 전달하게 됩니다. 그러나 HttpResponse 객체를 반환하게 되는 경우, 즉각적으로 process_response 메소드들을 호출하여 viewrequest를 전달하지 않고 즉각적으로 process_response 사이클을 실행하게 됩니다.

process_view(request, view_function, view_args, view_kwargs)

requestHttpRequest 객체이며, 호출할 view 함수와 view 함수에 전달할 인자들은 view_args,view_kwargs 입니다. process_view 메소드들은 view 함수를 실행하여 응답을 생성하기 전에 호출되며, process_request와 마찬기자로 None이나 HttpResponse를 응답으로 반환해야합니다.

None을 반환하는 경우에는 등록된 다른 process_view 메소드들을 실행하고 view 함수를 최종적으로 실행하여 응답을 생성하지만, HttpResponse 객체를 반환하는 경우에는 view 함수를 실행하지 않고 반환된 HttpResponse 객체를 처리하여 즉각적으로 응답으로 반환하게 됩니다.

process_response(request, response)

process_reponse 메소드에서는viewprocess_view가 반환되는 HttpResponse 객체를 다루게 됩니다. process_response 메소드들은 settings.py에 등록된 MIDDLEWARE의 역순으로 실행되며, 응답의 데이터를 마지막으로 수정할 수 있는 단계입니다.

process_exception(request, exception)

view에서 예외가 발생하게 되면, WSGI Handler는 등록된 process_exception 메소드들을 순차적으로 실행하여 예외를 처리하게 됩니다. process_exception 메소드들은 process_response와 마찬가지로 settings.py에 등록된 MIDDLEWARE의 역순으로 실행됩니다.

process_exception 메소드는 None 혹은 HttpResponse 객체를 반환해야합니다. HttpResponse 객체를 반환하게 되는 경우, 이후에 실행되는 다른 process_exception 메소드들은 실행되지 않고 응답을 처리하여 반환하게 됩니다. 이와 달리 None을 반환하는 경우에는 djangoexception handling가 실행됩니다.



Custom Middleware 구현

REST API 서버를 개발하며 서버 내부에서 에러가 발생하게 되는 경우, 500 응답을 반환하는 ErrorHandlerMiddleware를 구현해보겠습니다.

class ErrorHandlerMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
    	# 요청이 들어오게 되면 view 함수가 호출되기 전에 실행되는 코드 영역입니다.
        response = self.get_response(request) # view 함수가 실행되어 응답이 생성되는 부분입니다. 
    	# view 함수가 실행된 후, 실행되는 코드 부분입니다.
    	return response

    def process_exception(self, request, exception):
        if not settings.DEBUG:	# 개발환경에서는 기존의 에러 html template를 그대로 브라우저에 렌더링합니다.
            return HttpResponse(
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                content_type='application/json',
                content = json.dumps({
                    'status_code': status.HTTP_500_INTERNAL_SERVER_ERROR,
                    'message': 'Internal Server Error',
                    'data': {
                        'message': '서버 내부 오류입니다. 관리자에게 문의 부탁드립니다.'
                    }
                })
            )

process_exceptionview에서 에러가 발생하게 되면 실행됩니다. None을 반환하게되면 등록된 다른 process_exception 메소드들을 실행하고 Django의 기본 예외 핸들러가 개입하여 우리가 흔하게 마주하게되는 아래와 같은 html 템플릿을 렌더링하게 됩니다. 하지만 HttpResponse 객체를 반환하면 다른 process_exception 메소드들은 실행하지 않고 생성된 응답을 반환합니다.

{
    "status_code": 500,
    "message": "Internal Server Error",
    "data": {
        "message": "서버 내부 오류입니다. 관리자에게 문의 부탁드립니다."
    }
}



마무리

아마 django로 처음 개발을 하시는 분들은 대부분 views.py에 서비스의 로직을 구현하고, urls.py를 통해 구현한 로직을 url에 연동하는 작업을 하시는게 대부분이실 것으로 예상합니다. 하지만 Django가 지원하는 기능은 그보다 훨씬 다양하며, 단순한 client-server 모델뿐만 아니라 다양한 비동기 프로토콜도 지원하고 있습니다. 이러한 다양한 기능들을 사용하기 위해서는 Django의 구조와 구성 요소들이 무엇이며, 어떤 역할을 수행하며 다른 요소들로는 무엇이 있는지 알아야 다양한 기능 요구들을 충족할 수 있을 것이라고 생각합니다.



reference
post-custom-banner

0개의 댓글