1. 程式人生 > >Django 生命週期涉及知識點一網打盡 第一篇

Django 生命週期涉及知識點一網打盡 第一篇

1. 簡述Http協議?
    - 超文字傳輸協議
        - 特點:
            - 無狀態,請求響應之後,再次發起請求時,不認識。
            - 短連線,一次請求和一次響應就斷開連線。
        - 格式:
        
            - GET請求:輸入地址回車:https://passport.jd.com/new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F
                請求由兩部分組成:請求頭和請求體,請求頭和請求體通過\r\n\r\n分割,請求頭和請求頭之間通過\r\n分割。
                    
"""GET /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1\r\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36\r\nHost:jd.com\r\n\r\n""" 響應由兩部分組成:響應頭和響應體, b'HTTP/1.1 200 OK\r\nDate: Mon, 05 Nov 2018 01:15:31 GMT\r\nServer: Apache\r\nLast-Modified: Tue, 12 Jan 2010 13:48:00 GMT\r\nETag: "51-47cf7e6ee8400"\r\nAccept-Ranges: bytes\r\nContent-Length: 81\r\nCache-Control: max-age=86400\r\nExpires: Tue, 06 Nov 2018 01:15:31 GMT\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n <html><head> .... </html>
' - POST請求: 請求由兩部分組成:請求頭和請求頭 """POST /new/login.aspx?ReturnUrl=https%3A%2F%2Fwww.jd.com%2F http1.1\r\nUser-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36\r\nHost:jd.com\r\n\r\nusername=haoxu666&password=123
""" 響應: b'HTTP/1.1 200 OK\r\nDate: Mon, 05 Nov 2018 01:15:31 GMT\r\nServer: Apache\r\nLast-Modified: Tue, 12 Jan 2010 13:48:00 GMT\r\nETag: "51-47cf7e6ee8400"\r\nAccept-Ranges: bytes\r\nContent-Length: 81\r\nCache-Control: max-age=86400\r\nExpires: Tue, 06 Nov 2018 01:15:31 GMT\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n使用者名稱或密碼錯誤' 2. 你瞭解的請求頭都有什麼? - User-Agent,裝置資訊。 - Host,當前訪問的主機名稱。 - referrer,做防盜鏈。 - Content-Type: .... 3. 你瞭解的請求方式有哪些? - GET/POST/PUT/PATCH/DELETE/OPTIONS 4. django請求的生命週期/瀏覽器上輸入 http://www.oldboyedu.com 地址回車發生了什麼? - 瀏覽器輸入:http://www.oldboyedu.com 回車 - DNS解析,將域名解析成IP。 - 瀏覽器(socket客戶端),根據IP和埠(80)建立連線,傳送請求。 - 服務端接收請求 - 實現了wsgi協議的模組,如:wsgiref接收到使用者請求。 - 然後將請求轉交給django的中介軟體,執行中介軟體的process_request(process_view)。 - 路由系統進行路由匹配。 - 匹配成功執行檢視函式,檢視函式進行業務處理(ORM操作資料+模板渲染) - 交給中介軟體的process_response方法 - wsigref的socket.send,將結果返回給瀏覽器。 - 斷開socket連線。 - 瀏覽器斷開連線。 詳細:見django請求生命週期圖 5. 什麼是wsgi? wsgi,web服務閘道器介面,他是一套協議。 實現wsgi協議有: - wsgiref - uwsgi 實現wsgi協議的所有的模組本質:socket服務端。 6. django中介軟體的作用?應用場景? 中介軟體,可以對所有請求進行批量操作。 應用場景: - 自己玩 - 記錄日誌 - IP黑名單 - 許可權系統中的許可權校驗 - 解決跨域:編寫一箇中間件,在中介軟體中定義一個process_response,新增一個響應頭(CORS,跨站資源共享) - 使用者登入 - csrf_token驗證(django內建功能) 細節: - 5個方法:process_request/process_response + 3 - 執行流程 正常流程: - 所有process_request - 所有process_view - 所有process_response 非正常流程: - django 1.10及以後:平級返回 - django 1.10以前:找到最後的process_response - 寫程式碼時,如果忘記方法名稱或方法引數個數,怎麼辦? - 任意匯入一個原始碼檢視,如: # from django.middleware.common import CommonMiddleware MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] - 執行流程是如何實現的? 將中介軟體的相關方法新增到對應的 5個列表中,以後迴圈執行(順序、倒序) 原始碼: class BaseHandler(object): def __init__(self): self._request_middleware = None self._view_middleware = None self._template_response_middleware = None self._response_middleware = None self._exception_middleware = None self._middleware_chain = None def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE (or the deprecated MIDDLEWARE_CLASSES). Must be called after the environment is fixed (see __call__ in subclasses). """ self._request_middleware = [] self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] if settings.MIDDLEWARE is None: warnings.warn( "Old-style middleware using settings.MIDDLEWARE_CLASSES is " "deprecated. Update your middleware and use settings.MIDDLEWARE " "instead.", RemovedInDjango20Warning ) handler = convert_exception_to_response(self._legacy_get_response) for middleware_path in settings.MIDDLEWARE_CLASSES: mw_class = import_string(middleware_path) try: mw_instance = mw_class() except MiddlewareNotUsed as exc: if settings.DEBUG: if six.text_type(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if hasattr(mw_instance, 'process_request'): self._request_middleware.append(mw_instance.process_request) if hasattr(mw_instance, 'process_view'): self._view_middleware.append(mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.insert(0, mw_instance.process_template_response) if hasattr(mw_instance, 'process_response'): self._response_middleware.insert(0, mw_instance.process_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception) else: handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): middleware = import_string(middleware_path) try: mw_instance = middleware(handler) except MiddlewareNotUsed as exc: if settings.DEBUG: if six.text_type(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if mw_instance is None: raise ImproperlyConfigured( 'Middleware factory %s returned None.' % middleware_path ) if hasattr(mw_instance, 'process_view'): self._view_middleware.insert(0, mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.append(mw_instance.process_template_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.append(mw_instance.process_exception) handler = convert_exception_to_response(mw_instance) # We only assign to this when initialization is complete as it is used # as a flag for initialization being complete. self._middleware_chain = handler - 根據字串的形式匯入模組 + 根據反射找到模組中的成員 總結: 特點: - 所有請求都要通過中介軟體 - 5個方法 - 5個方法的執行流程 - 正常 - 不正常(版本區別) 應用場景: - 自己玩: - IP黑名單限制 - 日誌 - 工作場景: - 許可權控制 - 跨域 - 登入 - CSRF 相關知識點: - 流程實現原理:列表+列表翻轉 - 根據字串的形式匯入模組+反射 7. 路由系統 本質:儲存url和函式的對應關係。 相關知識點: 示例1: url(r'^index/', views.index), def index(request): return HttpResponse('...') 示例2: url(r'^user/edit/(\d+)/$', views.user_edit), def user_edit(request,nid): return HttpResponse('...') 示例3: url(r'^crm/', include('app01.urls')) from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^order/', views.order), url(r'^center/', views.center), ] def order(request): return HttpResponse('...') def center(request): return HttpResponse('...') 示例4:根據name別名反向生成URL urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls')), ] urlpatterns = [ url(r'^order/', views.order,name='order'), url(r'^center/', views.center,name='center'), ] 反向生成: index_url = reverse('index') user_edit_url = reverse('user_edit',args=('999',)) index_url = reverse('order') index_url = reverse('center') 示例5:根據 namespace + name 別名反向生成URL urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls',namespace='crm')), ] urlpatterns = [ url(r'^order/', views.order,name='order'), url(r'^center/', views.center,name='center'), ] 檢視中反向生成: index_url = reverse('index') user_edit_url = reverse('user_edit',args=('999',)) index_url = reverse('crm:order') index_url = reverse('crm:center') 在模板中反向生成: {% url 'index' %} {% url 'user_edit' 999 %} {% url 'crm:order' %} {% url 'crm:center' %} 補充:公司專案從路由開始看,可能你看到的是這樣。 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name='index'), url(r'^user/edit/(\d+)/$', views.user_edit,name='user_edit'), url(r'^crm/', include('app01.urls',namespace='crm')), ] urlpatterns += [ url(r'^xxxx/', views.index), ] 8. 什麼是MVC、MTV? MVC, Model View Controller MTV, Model Template View 9. FBV和CBV FBV,寫函式進行處理業務邏輯。 CBV,寫類進行處理業務邏輯。 本質上FBV和CBV都是一樣的,因為url對應都是一個函式。 url(r'^order/', views.order,name='order'), # 1. 對應order函式;2.一旦請求到來,立即執行order函式 url(r'^center/', views.CenterView.as_view(),name='center'), # 1. url對應 views.CenterView.as_view()會返回一個view函式;2. 請求到來之後,立即執行view函式,view由會觸發dispatch方法、dispatch會根據method不同根據反射執行get/post/delete...的方法。 推薦: 業務邏輯,FBV(簡單)。 restful api,CBV。 10. 現象:兩個系統之間進行相互資料傳輸,李超向講師機發送POST請求,但講師機的request.POST中沒有獲取到資料,可能是因為什麼? 1. csrf_token from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def api(request): """ 為李超提供的API介面 :param request: :return: """ print(request.POST) return HttpResponse('...') 例項程式碼: 李超.py: import requests response = requests.post('http://127.0.0.1:8000/crm/api/',data={'user':'alex','pwd':'dsb'}) print(response.text) Http請求格式: """POST /crm/api/ http\1.1\r\nhost:..\r\nContent-Type:application/x-www-form-urlencoded .....\r\n\r\nuser=alex&pwd=dsb""" django服務端: from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def api(request): """ 為李超提供的API介面 :param request: :return: """ print(request.POST) return HttpResponse('...') 2. request.POST解析時,有限制。 李超.py import requests response = requests.post('http://127.0.0.1:8000/crm/api/',json={'user':'alex','pwd':'dsb'}) print(response.text) Http請求格式: """POST /crm/api/ http\1.1\r\nhost:..\r\nContent-Type:application/json .....\r\n\r\n{'user':'alex','pwd':'dsb'}""" django服務端: @csrf_exempt def api(request): """ 為李超提供的API介面 :param request: :return: """ print(request.body) # 原生的請求體格式,有資料;(自己讀取body然後進行解析) print(request.POST) # 將原生的請求體轉換成 QueryDict物件,無資料。 return HttpResponse('...') 注意: request.POST 將原生的請求體轉換成 QueryDict物件,請求必須滿足兩個條件才能轉換: - Content-Type:application/x-www-form-urlencoded - 資料格式: user=alex&pwd=dbs&xxx=123 如果不滿足此條件,django獲取請求體時需要自己去request.body中獲取值。 總結: django獲取請求體 request.body request.POST是將請求體的資料轉換成了QueryDict物件。 11. 檢視函式的返回值 HttpResponse render 示例1: 檢視: def test(request): """ :param request: :return: """ return render(request,'test.html',{'k1':123}) test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <div> <h1>{{ k1 }}</h1> <script> alert('{{ k1 }}'); </script> </div> </body> </html> 示例2: 檢視: def test(request): """ :param request: :return: """ return render(request,'test.html',{'k1':123}) test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <div> <h1>{{ k1 }}</h1> <script src='/static/commons.js'></script> </div> </body> </html> commons.js alert('{{k1}}') redirect 將要重定向的地址通過響應頭Location響應頭返回給瀏覽器。