Django中url中可以使用类视图.as_view()进行映射的原因

说明:本人在学练习天天生鲜项目时,对利用类视图去与正则匹配到的url做映射有点疑惑,经过查看他人博客以及自我分析算是整明白了,所以记录一下

参考:https://www.zmrenwu.com/post/53/

HTTP发送请求的方式有很多种,这里以POST,GET为例。当在浏览器中输入url地址时(如http://127.0.0.1:8000/userr/register)

会进行正则匹配,并映射到ActiveView.as_view(),其最终达到能将注册页面显示出来的效果,原因如下:

class RegisterView(View):
    '''注册'''
    def get(self, request):
        '''显示注册页面'''
        return render(request, 'register.html')

    def post(self, request):
        '''进行注册处理'''
        '''进行注册处理'''
        # 接收数据
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')
        # 进行数据处理
        if not all([username, password, email]):
            return render(request, 'register.html', {'errmsg': '数据不完整'})
        # 校验邮箱
        if not re.match(r'^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return render(request, 'register.html', {'errmsg': '邮箱格式不正确'})

        # 校验协议
        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})
        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户不存在
            user = None

        # 进行业务处理: 进行用户注册
        user = User.objects.create_user(username, email, password)
        user.is_active = 0
        user.save()

        # 发送激活邮件
        serializer = Serializer(settings.SECRET_KEY, 3600)
        info = {'confirm':user.id}
        token = serializer.dumps(info) # bytes
        token = token.decode()
        # 发邮箱
        send_register_active_email.delay(email, username, token)
        # subject = '天天生鲜欢迎信息'
        # message = ''
        # sender = settings.EMAIL_FROM
        # receiver = [email]
        # html_message = '<h1>%s, 欢迎您成为天天生鲜注册会员</h1>请点击下面链接激活您的账户<br/><a href="http://127.0.0.1:8000/userr/active/%s">http://127.0.0.1:8000/userr/active/%s</a>' % (
        #     username, token, token)
        # send_mail(subject, message, sender, receiver, html_message=html_message)
        # 返回应答,跳转到首页
        return redirect(reverse('goods:index'))

  

RegisterView类中并没有as_view()方法,但其父类View中有as_view()方法,所以父类的此方法就被调用,父类View原码如下

class View(object):
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    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 six.iteritems(kwargs):
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
            if key in cls.http_method_names:
                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):
                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)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            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 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.
        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}
        )
        return http.HttpResponseNotAllowed(self._allowed_methods())

    def options(self, request, *args, **kwargs):
        """
        Handles responding to requests for the OPTIONS HTTP verb.
        """
        response = http.HttpResponse()
        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)]

dispatch()方法实现的功能如下:

首先它通过 request.method (即 HTTP 请求的方法)判断请求的方法是否是被 HTTP 协议所允许的。如果不合法,就会调用错误处理函数 self.http_method_not_allowed;如果请求方法是合法的,就会试图根据 request.method 去类中寻到对应的处理方法,如果找不到则还是委托给 self.http_method_not_allowed 处理。

代码实现过程:

当在浏览器中输入url地址时(如http://127.0.0.1:8000/userr/register),经过正则匹配以及映射关系,首先调用View.as_view()方法,接着调用as_view()方法中的view()方法,view()方法进一步调用View类内的dispatch()方法。,在dispatch()方法中,request.method判断出HTTP请求的方法为GET,request.method.lower()将GET转换为get,getattr方法将得到的get负值给handler,然后通过return handler()调用handler()方法,即为RegisterView类中的get()方法,而get()方法会返回模板中的html文件(即register.html)。其返回的结果依次return给方法的调用者,最终返回给View.as_view()方法的结果是模板中的register.html文件,即能显示出注册页面,如下

当点击注册时(填好相关信息),此时HTTP的请求方式变成POST,同理,最终也能显示出相应的页面(此处为显示首页)

猜你喜欢

转载自www.cnblogs.com/jj1106/p/10995309.html