a default context mixin that passes the keyword arguments received by getcontextdata as the template context intentionally simple parent class for all views only implements dispatchbymethod and simple sanity checking constructor called in the urlconf can contain helpful extra keyword arguments and other things go through keyword arguments and either save their values to our instance or raise an error main entry point for a requestresponse process for key in initkwargs if key in cls httpmethodnames raise typeerror the method name s is not accepted as a keyword argument to s key cls name if not hasattrcls key raise typeerror s received an invalid keyword r asview only accepts arguments that are already attributes of the class cls name key def viewrequest args kwargs self clsinitkwargs self setuprequest args kwargs if not hasattrself request raise attributeerror s instance has no request attribute did you override setup and forget to call super cls name return self dispatchrequest args kwargs view viewclass cls view viewinitkwargs initkwargs name and qualname are intentionally left unchanged as viewclass should be used to robustly determine the name of the view instead view doc cls doc view module cls module view annotations cls dispatch annotations copy possible attributes set by decorators e g csrfexempt from the dispatch method view dict updatecls dispatch dict mark the callback if the view class is async if cls viewisasync markcoroutinefunctionview return view def setupself 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 handle responding to requests for the options http verb response httpresponse response headersallow joinself allowedmethods response headerscontentlength 0 if self viewisasync async def func return response return func else return response def allowedmethodsself return m upper for m in self httpmethodnames if hasattrself m class templateresponsemixin return a response using the responseclass for this view with a template rendered with the given context pass responsekwargs to the constructor of the response class return a list of template names to be used for the request must return a list may not be called if rendertoresponse is overridden render a template pass keyword arguments from the urlconf to the context provide a redirect on any get request permanent false url none patternname none querystring false def getredirecturlself args kwargs if self url url self url kwargs elif self patternname url reverseself patternname argsargs kwargskwargs else return none args self request meta getquerystring if args and self querystring url s s url args return url def getself request args kwargs url self getredirecturlargs kwargs if url if self permanent return httpresponsepermanentredirecturl else return httpresponseredirecturl else logger warning gone s request path extrastatuscode 410 request request return httpresponsegone def headself request args kwargs return self getrequest args kwargs def postself request args kwargs return self getrequest args kwargs def optionsself request args kwargs return self getrequest args kwargs def deleteself request args kwargs return self getrequest args kwargs def putself request args kwargs return self getrequest args kwargs def patchself request args kwargs return self getrequest args kwargs a default context mixin that passes the keyword arguments received by get_context_data as the template context intentionally simple parent class for all views only implements dispatch by method and simple sanity checking constructor called in the urlconf can contain helpful extra keyword arguments and other things go through keyword arguments and either save their values to our instance or raise an error main entry point for a request response process __name__ and __qualname__ are intentionally left unchanged as view_class should be used to robustly determine the name of the view instead copy possible attributes set by decorators e g csrf_exempt from the dispatch method mark the callback if the view class is async initialize attributes shared by all view methods 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 handle responding to requests for the options http verb a mixin that can be used to render a template return a response using the response_class for this view with a template rendered with the given context pass response_kwargs to the constructor of the response class return a list of template names to be used for the request must return a list may not be called if render_to_response is overridden render a template pass keyword arguments from the urlconf to the context provide a redirect on any get request return the url redirect to keyword arguments from the url pattern match generating the redirect request are provided as kwargs to this method
import logging

from asgiref.sync import iscoroutinefunction, markcoroutinefunction

from django.core.exceptions import ImproperlyConfigured
from django.http import (
    HttpResponse,
    HttpResponseGone,
    HttpResponseNotAllowed,
    HttpResponsePermanentRedirect,
    HttpResponseRedirect,
)
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.decorators import classonlymethod
from django.utils.functional import classproperty

logger = logging.getLogger("django.request")


class ContextMixin:
    

    extra_context = None

    def get_context_data(self, **kwargs):
        kwargs.setdefault("view", self)
        if self.extra_context is not None:
            kwargs.update(self.extra_context)
        return kwargs


class View:
    

    http_method_names = [
        "get",
        "post",
        "put",
        "patch",
        "delete",
        "head",
        "options",
        "trace",
    ]

    def __init__(self, **kwargs):
        
        
        
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classproperty
    def view_is_async(cls):
        handlers = [
            getattr(cls, method)
            for method in cls.http_method_names
            if (method != "options" and hasattr(cls, method))
        ]
        if not handlers:
            return False
        is_async = iscoroutinefunction(handlers[0])
        if not all(iscoroutinefunction(h) == is_async for h in handlers[1:]):
            raise ImproperlyConfigured(
                f"{cls.__qualname__} HTTP handlers must either be all sync or all "
                "async."
            )
        return is_async

    @classonlymethod
    def as_view(cls, **initkwargs):
        
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError(
                    "The method name %s is not accepted as a keyword argument "
                    "to %s()." % (key, cls.__name__)
                )
            if not hasattr(cls, key):
                raise TypeError(
                    "%s() received an invalid keyword %r. as_view "
                    "only accepts arguments that are already "
                    "attributes of the class." % (cls.__name__, key)
                )

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            if not hasattr(self, "request"):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)

        view.view_class = cls
        view.view_initkwargs = initkwargs

        
        
        
        view.__doc__ = cls.__doc__
        view.__module__ = cls.__module__
        view.__annotations__ = cls.dispatch.__annotations__
        
        
        view.__dict__.update(cls.dispatch.__dict__)

        
        if cls.view_is_async:
            markcoroutinefunction(view)

        return view

    def setup(self, request, *args, **kwargs):
        
        if hasattr(self, "get") and not hasattr(self, "head"):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

    def dispatch(self, request, *args, **kwargs):
        
        
        
        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)

    def http_method_not_allowed(self, request, *args, **kwargs):
        logger.warning(
            "Method Not Allowed (%s): %s",
            request.method,
            request.path,
            extra={"status_code": 405, "request": request},
        )
        response = HttpResponseNotAllowed(self._allowed_methods())

        if self.view_is_async:

            async def func():
                return response

            return func()
        else:
            return response

    def options(self, request, *args, **kwargs):
        
        response = HttpResponse()
        response.headers["Allow"] = ", ".join(self._allowed_methods())
        response.headers["Content-Length"] = "0"

        if self.view_is_async:

            async def func():
                return response

            return func()
        else:
            return response

    def _allowed_methods(self):
        return [m.upper() for m in self.http_method_names if hasattr(self, m)]


class TemplateResponseMixin:
    

    template_name = None
    template_engine = None
    response_class = TemplateResponse
    content_type = None

    def render_to_response(self, context, **response_kwargs):
        
        response_kwargs.setdefault("content_type", self.content_type)
        return self.response_class(
            request=self.request,
            template=self.get_template_names(),
            context=context,
            using=self.template_engine,
            **response_kwargs,
        )

    def get_template_names(self):
        
        if self.template_name is None:
            raise ImproperlyConfigured(
                "TemplateResponseMixin requires either a definition of "
                "'template_name' or an implementation of 'get_template_names()'"
            )
        else:
            return [self.template_name]


class TemplateView(TemplateResponseMixin, ContextMixin, View):
    

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)


class RedirectView(View):
    

    permanent = False
    url = None
    pattern_name = None
    query_string = False

    def get_redirect_url(self, *args, **kwargs):
        
        if self.url:
            url = self.url % kwargs
        elif self.pattern_name:
            url = reverse(self.pattern_name, args=args, kwargs=kwargs)
        else:
            return None

        args = self.request.META.get("QUERY_STRING", "")
        if args and self.query_string:
            url = "%s?%s" % (url, args)
        return url

    def get(self, request, *args, **kwargs):
        url = self.get_redirect_url(*args, **kwargs)
        if url:
            if self.permanent:
                return HttpResponsePermanentRedirect(url)
            else:
                return HttpResponseRedirect(url)
        else:
            logger.warning(
                "Gone: %s", request.path, extra={"status_code": 410, "request": request}
            )
            return HttpResponseGone()

    def head(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def options(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.get(request, *args, **kwargs)