• CBV(class base views)之继承View源码解析


    CBV继承View 之View源码解析:

    CBV:基于类的视图,就是在视图里使用类处理请求。

    优点:继承了所有面向对象的属性(继承、封装、多态)。

    CBV提供了一个静态方法as_view(),调用这个方法会创建一个实例,然后再调用dispatch()方法,dispatch()会根据request的method的不同,从而调用相对应的方法来处理request(get,post....)。

    View的属性和方法如下:

    • 属性
      • args
      • kwargs
      • request
      • http_method_names
    • 方法
      • as_view
      • setup
      • dispatch
      • http_method_not_allowed
      • options
        • 默认支持options请求
        • 显示此接口都支持哪些请求
    在源码中带了注释,方便各位学习:
    class View:
        """
        Intentionally simple parent class for all views. Only implements
        dispatch-by-method and simple sanity checking.
        """
        # view中所有请求方法的名字
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
        def __init__(self, **kwargs):
            """
            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.
            for key, value in kwargs.items():
                setattr(self, key, value)
    
        @classonlymethod	# 此类方法仅仅在类中能被使用
        def as_view(cls, **initkwargs):		# **initkwargs: 能接收关键字参数
            """Main entry point for a request-response process."""
            for key in initkwargs:
                if key in cls.http_method_names:	# 如果key是该方法内的请求方法名字
    		# 翻译:您试图将%s方法名作为“”关键字参数传递给%s()。别这么做。”
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):		# key 必须是已存在的属性
                    # 翻译:“%s()收到一个无效的关键字%r。as_view”“只接受已经是该类的”“属性的参数。
                    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)	# 构建一个对象
                # 如果有get方法同时没有head方法
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    # 则 head方法 与 get方法相同
                    self.head = self.get
                # 跳转函数 >> setup >> 初始化所有视图方法共享的属性,记录参数 self.request = request
                self.setup(request, *args, **kwargs)
                
                # 如果没有request,报异常
                if not hasattr(self, 'request'):
                    # 翻译:如果没有request,你是不是重写了setup(),并且没有调用super().
                    raise AttributeError(
                        "%s instance has no 'request' attribute. Did you override "
                        "setup() and forget to call super()?" % cls.__name__
                    )
                # 获取所有属性之后进入dispatch函数 
                return self.dispatch(request, *args, **kwargs)
            
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    
        def setup(self, request, *args, **kwargs):
            """Initialize attributes shared by all view methods."""
            self.request = request
            self.args = args
            self.kwargs = kwargs
    
        def dispatch(self, 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.
            
            # 判断 请求方法名字 小写是否在 view中所有请求方法
            if request.method.lower() in self.http_method_names:
                # 获取到我们自己编写的方法(函数,key值,default=默认值),没有则调用默认值
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                # 请求方法不在View内置请求方法中,跳转下一个函数 >> 请求方法不被允许
                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}
            )
            # 返回的HttpResponseNotAllowed子类,请求方法不被允许
            return HttpResponseNotAllowed(self._allowed_methods())
    
        def options(self, request, *args, **kwargs):
            # 处理对选项HTTP谓词的请求的响应
            """Handle responding to requests for the OPTIONS HTTP verb."""
            
            response = HttpResponse()
            # 默认支持option请求
            response['Allow'] = ', '.join(self._allowed_methods())
            response['Content-Length'] = '0'
            return response
    
        def _allowed_methods(self):
            return [m.upper() for m in self.http_method_names if hasattr(self, m)]
    
    
  • 相关阅读:
    Chapter 1 First Sight——8
    Chapter 1 First Sight——7
    Chapter 1 First Sight——6
    Chapter 1 First Sight——5
    PAT1012
    Chapter 1 First Sight——4
    Chapter 1 First Sight——3
    需要注意的subList方法!和substring是不一样的!从源码解释他们的不同。
    餐桌项目删除餐桌
    addEventListener()绑定事件的对象方法。
  • 原文地址:https://www.cnblogs.com/lance-lzj/p/13845418.html
Copyright © 2020-2023  润新知