수색…


소개

Django의 미들웨어는 코드가 응답 / 요청 처리에 연결하여 장고의 입력 또는 출력을 변경할 수있게 해주는 프레임 워크입니다.

비고

미들웨어는 실행에 포함되기 전에 settings.py MIDDLEWARE_CLASSES 목록에 추가해야합니다. Django가 새로운 프로젝트를 생성 할 때 제공하는 기본 목록은 다음과 같습니다.

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

이들은 모든 요청에 ​​대해 순서대로 실행되는 모든 함수입니다 (한 번 views.py 에서보기 코드에 도달하기 전에 한 번, process_response 콜백의 역순으로 버전 1.10 이전에). 크로스 사이트 요청 위조 (csrf) 토큰을 주입하는 등 다양한 작업을 수행합니다.

어떤 미들웨어가 리다이렉트를하면 그 이후의 모든 미들웨어는 절대로 실행되지 않기 때문에 순서가 중요하다. 미들웨어가 csrf 토큰을 기대한다면 CsrfViewMiddleware 뒤에 실행 CsrfViewMiddleware 합니다.

요청에 데이터 추가

Django는 뷰 내에서 사용할 요청에 추가 데이터를 추가하는 것을 매우 쉽게 만듭니다. 예를 들어 요청의 META에서 하위 도메인을 파싱하고 미들웨어를 사용하여 요청시 별도의 속성으로 연결할 수 있습니다.

class SubdomainMiddleware:
    def process_request(self, request):
        """
        Parse out the subdomain from the request
        """
        host = request.META.get('HTTP_HOST', '')
        host_s = host.replace('www.', '').split('.')
        request.subdomain = None
        if len(host_s) > 2:
            request.subdomain = host_s[0]

요청에 미들웨어가 포함 된 데이터를 추가하면 새로 추가 된 데이터에 액세스 할 수 있습니다. 여기에서는 파싱 된 하위 도메인을 사용하여 조직이 애플리케이션에 액세스하는 것과 같은 것을 결정합니다. 이 접근법은 단일 인스턴스를 가리키는 와일드 카드 하위 도메인과 함께 DNS 설정으로 배포 된 앱에 유용하며 앱에 액세스하는 사람은 액세스 포인트에 종속 된 스킨 버전을 원합니다.

class OrganizationMiddleware:
    def process_request(self, request):
        """
        Determine the organization based on the subdomain
        """
        try:
            request.org = Organization.objects.get(domain=request.subdomain)
        except Organization.DoesNotExist:
            request.org = None

미들웨어가 서로 의존 할 때 순서가 중요하다는 것을 기억하십시오. 요청의 경우 의존성 미들웨어가 종속성 뒤에 배치되기를 원할 것입니다.

MIDDLEWARE_CLASSES = [
    ...
    'myapp.middleware.SubdomainMiddleware',
    'myapp.middleware.OrganizationMiddleware',
    ...
]

IP 주소로 필터링 할 미들웨어

첫 번째 : 경로 구조

가지고 있지 않다면 다음과 같은 구조로 미들웨어 폴더를 만들어야합니다 :

yourproject/yourapp/middleware

폴더 미들웨어는 settings.py, urls, templates ...와 같은 폴더에 있어야합니다.

중요 사항 : 미들웨어 폴더 내에 init .py 빈 파일을 생성하여 앱이이 폴더를 인식하도록 잊지 마세요.

미들웨어 클래스를 포함하는 별도의 폴더를 가지는 대신, yourproject/yourapp/middleware.py 라는 단일 파일에 함수를 넣는 것도 가능합니다 .

두 번째 : 미들웨어 생성

이제 우리는 커스텀 미들웨어를위한 파일을 생성해야합니다. 이 예에서는 IP 주소를 기반으로 사용자를 필터링하는 미들웨어가 필요하다고 가정하고 filter_ip_middleware.py 라는 파일을 만듭니다.

#yourproject/yourapp/middleware/filter_ip_middleware.py
from django.core.exceptions import PermissionDenied    

class FilterIPMiddleware(object):
    # Check if client IP address is allowed
    def process_request(self, request):
        allowed_ips = ['192.168.1.1', '123.123.123.123', etc...] # Authorized ip's
        ip = request.META.get('REMOTE_ADDR') # Get client IP address
        if ip not in allowed_ips:
            raise PermissionDenied # If user is not allowed raise Error

       # If IP address is allowed we don't do anything
       return None

셋째 : 우리의 'settings.py'

settings.py에서 MIDDLEWARE_CLASSES 를 찾아야하고 거기에 미들웨어를 추가해야합니다 ( 마지막 위치에 추가 ). 그것은 다음과 같아야합니다 :

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
     # Above are Django standard middlewares

     # Now we add here our custom middleware
     'yourapp.middleware.filter_ip_middleware.FilterIPMiddleware'
)

끝난! 이제 모든 클라이언트의 모든 요청이 사용자 정의 미들웨어를 호출하고 사용자 정의 코드를 처리합니다!

전역 적 예외 처리

변경 사항을 제출 한 클라이언트가 최신 수정 사항을 가지고 있지 않은 동안 데이터베이스의 객체 수정 시도를 탐지하는 로직을 구현했다고 가정 해보십시오. 이러한 경우가 발생하면 사용자 정의 예외 ConfictError(detailed_message) 합니다.

이제이 오류가 발생할 때 HTTP 409 (Confict) 상태 코드를 반환하려고합니다. 일반적으로이 예외를 발생시킬 수있는 각 뷰에서이를 처리하는 대신 미들웨어로 사용할 수 있습니다.

class ConfictErrorHandlingMiddleware:
    def process_exception(self, request, exception):
        if not isinstance(exception, ConflictError):
            return  # Propagate other exceptions, we only handle ConflictError
        context = dict(confict_details=str(exception))
        return TemplateResponse(request, '409.html', context, status=409)

Django 1.10 미들웨어의 새로운 스타일 이해하기

Django 1.10에서는 process_requestprocess_response 가 함께 병합되는 새로운 미들웨어 스타일을 도입했습니다.

이 새로운 스타일에서 미들웨어는 다른 호출 가능 객체를 반환하는 호출 가능 객체 입니다. 글쎄, 실제로는 전자는 미들웨어 공장 이고 후자는 실제 미들웨어 입니다.

미들웨어 팩토리 는 미들웨어 스택의 다음 미들웨어 를 단일 인수로 취하고, 스택의 맨 아래에 도달하면 뷰 자체를 취합니다.

미들웨어 는 요청을 하나의 인수 HttpResponse 항상 HttpResponse 반환합니다 .

새로운 스타일의 미들웨어가 작동하는 방식을 보여주는 가장 좋은 예는 아마도 이전 버전과 호환되는 미들웨어 를 만드는 방법을 보여주는 것입니다.

class MyMiddleware:

    def __init__(self, next_layer=None):
        """We allow next_layer to be None because old-style middlewares
        won't accept any argument.
        """
        self.get_response = next_layer

    def process_request(self, request):
        """Let's handle old-style request processing here, as usual."""
        # Do something with request
        # Probably return None
        # Or return an HttpResponse in some cases

    def process_response(self, request, response):
        """Let's handle old-style response processing here, as usual."""
        # Do something with response, possibly using request.
        return response

    def __call__(self, request):
        """Handle new-style middleware here."""
        response = self.process_request(request)
        if response is None:
            # If process_request returned None, we must call the next middleware or
            # the view. Note that here, we are sure that self.get_response is not
            # None because this method is executed only in new-style middlewares.
            response = self.get_response(request)
        response = self.process_response(request, response)
        return response


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow