11_04、Django請求生命週期流程圖
一、Django請求生命週期流程圖
二、路由層
1、路由檔案
專案中url.py檔案中,新增路由設定
urlpatterns = [ url(r'^test/', views.test), ]
r'^test/' # 正則表示式,匹配以test開頭,以/結尾的字元,r是去掉轉義符,保證斜槓只是斜槓字元,而不會發生轉義
views.test # view.py檔案中的test函式記憶體地址
注意:settings.py檔案中的APPEND_SLASH控制斜槓自動匹配
APPEND_SLASH = True # 控制斜槓自動匹配(預設) APPEND_SLASH = False #取消斜槓自動匹配
2、有名分組和無名分組
1.什麼是分組
有名分組和無名分組是正則分組的兩種形式。
分組是通過括號把正則表示式括起來,特徵是組內優先展示。
路由檔案中的r'^test/'是一個正則表示式,所以也可以通過有名分組和無名分組的方式書寫
2.為什麼要用到分組
url中的前半部分(r'^test/'),是使用者輸入的網址字尾。
是為了給後半部分(views.test)這個函式名的記憶體地址匹配。
通過正則分組可以作為位置實參給函式傳參
但是注意,有幾個分組(引數),函式內就必須有相應的位置形參用於接收。
3、例項演示
有名分組:
# url.py檔案 urlpatterns = [ url(r'^test/(\d+)/(\a+)', views.test), ]
# view.py檔案 def test(request, first, second): print(first) # (\d+)匹配的內容 print(second) # (\a+)匹配的內容 return render(request, 'test.html', locals())
無名分組:
# url.py檔案 urlpatterns = [ url(r'^test/(?P<year>\d+)/(?P<month>\a+)', views.test), #有名分組,給正則名稱:year,month ]
# view.py檔案 def test(request, first, second): print(first) # (\d+)匹配的內容是關鍵字year print(second) # (\a+)匹配的內容匹配的內容是關鍵字month return render(request, 'test.html', locals())
注意:如果引數太多,可以用*args,**kwargs接收
# view.py檔案 def test(request, args, **kwargs): print(*args) print(**kwargs) return render(request, 'test.html', locals())
3、反向解析
1、起別名
針對過長匹配的url,我們可以用name給其重新命名
urlpatterns = [ url(r'^test/test1/test2/test3/', views.test, name='test'), # 給r'^test/test1/test2/test3/'重新命名為test ]
2、反向解析
反向解析就是通過name反向解析出原來的url
後端反向解析
# view.py檔案 from django.shortcuts import reverse def test(request): print(reverse('test')) # /test/test1/test2/test3/ return render(request, 'test.html', locals())
前端反向解析
# test.html檔案 <body> <a href="{% url 'test' %}">前端反向解析</a> </body>
無名分組前端反向解析
無名分組後端反向解析
有名分組前端反向解析
有名分組後端反向解析
4、路由分發
1、為什麼要路由分發
隨著時間和使用者的增多,我們的Django專案也會越來越大,那麼毫無疑問我們的總路由檔案也會也來越大
這會導致專案非常難以維護,為此我們會把總路由分開到不同的應用下面去,這是受Django框架支援的。
Django支援每個應用下面有自己的:
# 1、url.py檔案 # 2、static資料夾 # 3、templates資料夾
2、怎麼路由分發
第一步:
把總路由複製到各個應用中,並修改
# app02中的urls.py from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
# app02中的urls.py from django.conf.urls import url from django.contrib import admin from app03 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
第二步:總路由分發(include)
方式一:
""" 總路由檔案urls.py 匯入include 給分路由重新命名 """ from django.conf.urls import url, include from django.contrib import admin from app01 import views from app02 import urls as app02_url from app03 import urls as app03_url # url.py檔案 urlpatterns = [ # 總路由分發 url(r'^app02/', include(app02_url),), url(r'^app03/', include(app03_url),), ]
方式二:
""" 總路由檔案urls.py 無需匯入 """ from django.conf.urls import url, include from django.contrib import admin from app01 import views # url.py檔案 urlpatterns = [ url(r'^app02/', include('app02.urls')), url(r'^app03/', include('app03.urls')), ]
第三步:效果展示
檢視app02
檢視app03
5、名稱空間
我們再給路由起別名的時候,如果兩個url命名為相同的名字
在根據別名反向解析的時候,預設解析的是最後一個
如果要精準解析,這裡就要用到名稱空間的知識了(namespace = '自定義名稱空間名字')
# 總路由檔案urls.py urlpatterns = [ url(r'^app02/', include('app02.urls', namespace='app02')), url(r'^app03/', include('app03.urls', namespace='app03')), ]
方向解析的時候
from django.shortcuts import render,HttpResponse,reverse def index(request): print(reverse('app02:test')) return HttpResponse('app02:index')
三、虛擬環境
應用於多個多個專案,每個專案需要應用不同的模組、版本。
虛擬環境就是一個純淨版的python直譯器,我們可以在這個虛擬環境上安裝每個應用需要的外掛
我們可以同時擁有多個虛擬環境
四、JsonResponse(json序列化)
json格式的資料用於跨語言傳輸,
序列化就是通過json通過把各種格式的語言轉換成二進位制,
反序列化就是通過json把二進位制語言轉換成各種格式的語言
後端中的序列化和反序列化:
序列化:json.dumps
反序列化:json.loads
前端中的序列化和反序列化:
序列化:JSON.stringify()
反序列化:JSON.parse()
注意:
前後端分離的專案,需要永達json格式的資料
混合專案開發專案,用不到json格式的資料
django框架通過對json進一步封裝,方便了我們實現資料的序列和反序列化
from django.http import JsonResponse def my_json(request): my_dict = {'username': '魯迅', 'gender': 'male'} # 字典型別 my_list = [1, 2, 3] # 非字典型別 # res = json.dumps(my_dict, ensure_ascii=False) # json轉碼 # return HttpResponse(res) # json序列化 # return JsonResponse(my_json, json_dumps_params={'ensure_ascii': False}) # 字典型別的序列化 return JsonResponse(my_list, safe=False) # 非字典型別的序列化
五、CBV的書寫
CBV和FBV是一個概念的東西
FBV:function base views,顧名思義,基於檢視的函式(views.py中的函式)
CBV:class base views,同理,基於檢視的類(views.py中的類)
'''views.py檔案''' # cbv必須繼承View類 from django.views import View class IndexClass(View): # 注意類中的方法名必須指定為八種請求方式中的一種,不能隨意指定 # 八種方式:get post push def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
'''urls.py''' urlpatterns = [ url(r'^my_cbv/', views.IndexClass.as_view()), ]
六、CBV的原始碼分析
七、form表單上傳檔案
之前我們學過get請求和post請求可以通過request.get和request.post接收請求資料
檔案也有自己的接收方式:request.FILES
'''views.py檔案''' def my_form(request): if request.method == 'POST': print(request.GET) # get請求的物件request.GET,此處為<QueryDict: {}> print(request.POST) # post請求的物件request.POST,此處為<QueryDict: {}> print(request.FILES) # 檔案物件在request.FILES,<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 測試圖片.png (image/png)>]}> # request.FILES只接收檔案資料,其他請求一概不接收 # 字典取值 file_obj = request.FILES.get('myfile') print(file_obj.name) # 檔案的名稱:微信截圖_20220313203813.png # 上傳檔案 with open(file_obj.name, 'wb') as f: # 上傳檔案的時候要一行一行讀取,防止記憶體溢位 for line in file_obj: f.write(line) # 上傳的檔案存放在專案的根目錄 return render(request, 'my_form.html')
{# HTML檔案 #} {#注意:form表單上傳檔案的兩個必須條件method="post" enctype="multipart/form-data"#} <form action="" method="post" enctype="multipart/form-data"> <p> 上傳檔案:<input type="file" name="myfile"> </p> <input type="submit" value="提交"> </form>
'''urls.py檔案''' urlpatterns = [ url(r'^my_form/', views.my_form), # 上傳圖片 ]
注意:上傳的檔案存放在專案根目錄 ,但是再次上傳圖片檔案,會把原先上傳的覆蓋掉
我們可以通過匯入隨機數重新命名,解決這個問題
'''views.py檔案''' def my_form(request): if request.method == 'POST': print(request.GET) # get請求的物件request.GET,此處為<QueryDict: {}> print(request.POST) # post請求的物件request.POST,此處為<QueryDict: {}> print(request.FILES) # 檔案物件在request.FILES,<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 測試圖片.png (image/png)>]}> # request.FILES只接收檔案資料,其他請求一概不接收 # 字典取值 file_obj = request.FILES.get('myfile') print(file_obj.name) # 檔案的名稱:微信截圖_20220313203813.png import uuid rend_str = uuid.uuid4() file_path = str(rend_str) + '.png' # 上傳檔案 with open(file_path, 'wb') as f: # 上傳檔案的時候要一行一行讀取,防止記憶體溢位 for line in file_obj: f.write(line) # 上傳的檔案存放在專案的根目錄 return render(request, 'my_form.html')