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,同理,最終也能顯示出相應的頁面(此處為顯示首頁)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM