# 요청 발생 시 위에서 아래로 진행되면서 process_request() 실행
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 응답값 생성 시 밑에서 위로 진행되면서 process_response() 실행

def __call__(self, request):
    ...
    response = None
    if hasattr(self, 'process_request'):
        response = self.process_request(request)    
    response = response or self.get_response(request)
    if hasattr(self, 'process_response'):
        response = self.process_response(request, response)
    return response

Middleware

class CommonMiddleware(MiddlewareMixin):
		def process_request(self, request: WSGIRequest): -> None | HttpResponse
				...
				
		def process_response(self, request: WSGIRequest, response: HttpResponse): -> HttpResponse
				...
				
		def process_view(self, request: WSGIRequest, callback: Callable, callback_args, callback_kwargs): -> None | HttpResponse
				...

MiddlewareMixin

# from django.utils.deprecation import MiddlewareMixin

class MiddlewareMixin:
    sync_capable = True
    async_capable = True

    def __init__(self, get_response: Callable):
		    ...
		    self.get_response = get_response
		    
    def __call__(self, request):
		    ...
		    response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        
				# load_middleware가 실행될 때 self.get_response에 이전 middleware(mw_instance)가 저장됨
				# self.get_response = 이전 mw_instance가 들어있고,
				# 마지막 mw_instance.get_response에는 BaseHandler._get_response 메소드가 들어있음
				# 미들웨어의 __call__ 메소드는 WSGIHandler.get_response 안에서 호출됨(middleware.get_response 아님)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

WSGIHandler

# from django.core.handlers.wsgi import WSGIHandler

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()  # 미들웨어 메소드 체인 셋팅
        
    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)
        
class BaseHandler:
		...

    def get_response(self, request):
        set_urlconf(settings.ROOT_URLCONF)
        # middleware chain 실행: 실제 응답값이 만들어지는 시점(아래 참고)
        response = self._middleware_chain(request)
        response._resource_closers.append(request.close)
        if response.status_code >= 400:
            log_response(
                '%s: %s', response.reason_phrase, request.path,
                response=response,
                request=request,
            )
        return response
        
def convert_exception_to_response(get_response):
		if:
				...
    else:
        @wraps(get_response)
        def inner(request):
            try:
		            # get_response() == mw_instance.__call__ 메소드 호출
                response = get_response(request)
            except Exception as exc:
                response = response_for_exception(request, exc)
            return response
        return inner