談談Python之Django搭建企業級官網(第三篇上部)
轉載請註明來源地址和原作者(CFishHome)
前沿
上一節的學前準備工作和第一個小牛試刀的Django專案學習,讓我們對Django開發越來越感興趣了。正所謂趁熱打鐵,讓我們繼續來學習網站開發必備的檢視函式和URL對映等知識,跟著步伐一起學習,我相信你會收穫很多。噔~噔,新聞播報時間:9月12-9月16有兩個超強颱風在廣東湛江登陸,沿途影響眾多城市,包括深圳!!所以很遺憾,前幾天打算和舍友去深圳遊玩的計劃泡湯了,也只能推遲幾天前往深圳度中秋、看月亮了~
DEBUG模式
無論是使用命令列還是Pycharm建立Django專案工程,settings.py檔案的DEBUG都預設設定為True,所以預設是開啟了DEBUG模式。如下圖所示:

開啟DEBUG模式有以下好處:
1.我們可以發現,在Django開發時,頻繁修改檔案程式碼,然後要關閉專案,再重啟專案才能測試我們修改的程式碼。但是如果開啟了DEBUG模式,那麼以後我們修改了Django專案的程式碼,然後按下了ctrl+s,那麼Django就會自動的給我們重啟專案,不需要手動關閉再重啟。
2.如果開啟了DEBUG模式,那麼以後Django專案中的程式碼出現bug了,那麼在瀏覽器和控制檯會打印出錯資訊。
3.在實際將專案釋出到網上給其他使用者使用時,禁止開啟DEBUG模式,因為前面說了入宮出現bug會在瀏覽器和控制檯打印出錯資訊,這無疑把程式碼洩露在網上,會有很大的安全隱患。
4.如果DEBUG設定為False,那麼必須設定ALLOWED_HOSTS。前一篇說過,如果將host設定為0.0.0.0,那麼只能通過ALLOWED_HOSTS設定的IP地址進行訪問該專案,也可以設定多個IP地址。ALLOWED_HOSTS欄位如下圖位置:

URL分發器
我們在學習前先回顧下我們上一篇做了什麼。上一篇我們首先在Pycharm建立了一個名為first_project的Django專案,然後在CMD使用命令建立了一個名為my_app的app應用。注意,上篇因測試需要修改了IP地址和埠號,所以這裡我將專案的IP地址和埠號修改回127.0.0.1:8000,說明訪問這個IP就可以訪問我們的專案了。整體框架如下圖所示:

檢視
檢視其實就是檢視函式,它一般都寫在 app 的 views.py 檔案中,也就是我們my_app包裡的views.py檔案。並且檢視函式的第一個引數永遠都是 request (一個HttpRequest)物件。這個物件儲存了請求過來的所有信息,包括攜帶的引數以及一些頭部資訊等。在檢視中,一般是完成邏輯相關的操作。比如這個請求是新增一篇部落格,那麼在檢視函式可以通過request來接收到這些資料,然後儲存到資料庫中,最後再把函式執行的結果返回給瀏覽器。檢視函式的返回結果必須是 HttpResponseBase 物件或者子類的物件。
我們開啟my_app的views.py檔案,新增以下程式碼:
from django.http import HttpResponse # book_list是我們定義的一個檢視函式,第一個引數必須是request物件,並且該函式返回必須是 HttpResponseBase物件或者子類的物件。 def book_list(request): return HttpResponse("書籍列表!")
上面檢視函式返回的 HttpResponse("書籍列表!")只是單純的在網頁上輸出"書籍列表!"文字內容。
URL對映
檢視函式寫完後,我們怎麼實現讓使用者在瀏覽器中輸入一個URL就可以訪問到我們剛才寫的檢視函式,即使用者在瀏覽器一輸入某URL,網頁就顯示"書籍列表!"文字內容。
URL對映原理:使用者在瀏覽器輸入了某個 URL ,請求到我們的網站的時候, django 會從專案的 urls.py 檔案中尋找對應的檢視。為什麼會是在urls.py檔案中尋找對映呢?這是因為在"settings.py"檔案中配置了"ROT_URLCONF"為"urls.py"。在 urls.py 檔案中有一個 urlpatterns 變數,以後 django 就會從這個變數中讀取所有的匹配規則。匹配規則需要使用 django.urls.path 函式進行包裹,這個函式會根據傳入的引數返回 URLPattern 或者是 URLResolver 的物件。
修改first_project專案的 urls.py 檔案程式碼,示例程式碼如下:
from django.contrib import admin from django.urls import path from my_app import views# 匯入my_app包的views.py模組 urlpatterns = [ path('admin/', admin.site.urls), path('book/', views.book_list) ]
執行first_project專案,在瀏覽器輸入127.0.0.1:8000/book,訪問成功!如下圖所示(圖片左下角顯示了"書籍列表!"文字內容):

到了這裡朋友們可能會好奇如果輸入127.0.0.1:8000會怎麼樣?滿足你的好奇心,結果如下:

我的天!我按照上一篇的流程可以訪問的啊,怎麼現在不彳亍了。其實當新添加了第一個URL對映之後需要注意的是主網頁127.0.0.1:8000的網頁404丟失了,這是因為如果剛開始建立的專案,若還未新增過URL對映,那麼預設Django的底層提供一個就是那個火箭??頁面來對映,但若添加了,那麼就無法繼續對映那個火箭??頁面了,因為看urlpatterns變數其實都沒有對映空URL,即127.0.0.1:8000為空URL。
為URL傳遞引數
為URL傳遞引數有三種方式:
1.URL中新增引數 2.查詢字串傳遞引數 3.指定預設的引數
URL中新增引數
有時候, url 中包含了一些引數需要動態調整。比如簡書某篇文章的詳情頁的url,是 ofollow,noindex" target="_blank">https://www.jianshu.com/p/a5aab9c4978e 後面的 a5aab9c4978e 就是這篇文章的 id ,那麼簡書的文章詳情頁面的url就可以寫成 https://www.jianshu.com/p/<id> ; ,其中id就是文章的id。那麼如何在 django 中實現這種需求呢。這時候我們可以在 path 函式中,使用尖括號的形式來定義一個引數,也可以多個引數。比如我現在想要獲取一本書籍的詳細資訊,那麼應該在 url 中指定這個引數。first_project專案urls.py檔案的示例程式碼如下:
from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/<book_id>/',views.book_detail)# <book_id>就是引數 ]
採用在URL中使用變數的方式,在path函式的第一個引數中,使用“<引數名>”的方式可以傳遞引數,然後在檢視函式中也要寫一個函式來進行對映,檢視函式中的引數必須和URL中的引數名稱保持一致,不然就找不到這個引數(檢視函式第一個引數是request,那麼第二個引數就是book_id)。
而my_app包的views.py 中的程式碼如下:
# 該檢視函式與'book/<book_id>/'進行URL對映,並且檢視函式第二個引數必須同名 def book_detail(request,book_id): text = "您輸入的書籍的id是:%s" % book_id return HttpResponse(text)
執行結果如下:

對於多個引數也同樣類似,這裡不再測試。只不過在URL中新增多個引數,然後檢視函式新增多個同名引數來接收。
查詢字串傳遞引數
另一種方式是通過查詢字串的方式傳遞一個引數過去。在設定URL時,不需要單獨的匹配查詢字串的部分,只需要在檢視函式中使用request.GET.get('引數名稱')的方式來獲取。因為查詢字串使用的是“GET”請求,所以我們通過“request.GET”來獲取引數。
first_project專案的urls.py檔案的示例程式碼如下:
urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/<int:book_id>/',views.book_detail),# <book_id>就是引數,注意book_id前面還添加了個int轉換器,這裡只要我們知道這是限制輸入的id只能是整型即可,後面會詳細講解轉換器的作用。 path('book/pub/',views.book_pub) ]
在 my_app包中的views.py 後面新增如下程式碼:
def book_pub(request): pub_id = request.GET.get("id") text = "您輸入的出版社id是:%s" % pub_id return HttpResponse(text)
以後在瀏覽器輸入127.0.0.1:8000/book/pub/?id=1 即可將引數傳遞過去。
執行結果如下:

我們做個小測試,如果將轉換器Int去掉的話,我們還能成功訪問到嘛?將urls.py檔案程式碼修改如下:
urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/<book_id>/',views.book_detail), path('book/pub/',views.book_pub) ]
執行結果如下:

通過上圖可以發現,跟我們預期的不太一樣,我們在瀏覽器輸入的URL( http://127.0.0.1:8000/book/pub/?id=200 ) 被book_detail檢視函式捕獲了,這說明pub後面的所有字串都被認為是傳遞到book_detail檢視函式。
指定預設的引數
使用 path 後,在path的第一個引數可以包含引數,而有時候想指定預設的引數,這時候可以通過以下方式來完成,以下程式碼僅供理解預設引數的使用,在我們的實際專案中沒有此程式碼。
from django.urls import path from . import views urlpatterns = [ path('blog/', views.page), path('blog/page<int:num>/', views.page), ] # View (in blog/views.py) def page(request, num=1): # Output the appropriate page of blog entries, according to num.
上面'blog/page<int:num>/',引數前面多了個page,代表輸入URL時需要新增page,例如:’127.0.0.1:8000/blog/page100‘。所欲,如果你只寫’127.0.0.1:8000/blog/page',那麼將使用預設引數,num值為1。
預設引數的使用規則如下:
1.當用戶訪問一個URL不含有變數的時候,對映到檢視函式
並且檢視函式的形參有一個預設引數含有值,檢視函式就直
接使用這個預設引數。
2.當用戶訪問一個URL含有變數的時候,對映到檢視函式並
且檢視函式的形參有一個預設引數含有值,檢視函式就不使
用預設引數的值,而是採用URL匹配規則傳進來的值。
總結:其實上面的預設函式使用規則和程式語言函式的預設
引數使用規則類似。
轉換器
前一節我們簡單使用了int轉換器將同級的兩種傳遞引數的方式區分開來,不然查詢字串方式會被第一種傳遞引數方式所捕獲。
我們的轉換器是用在path函式中,所以有必要簡單介紹下path函式,這裡只簡單介紹第一個引數,後面會詳細講path函式的使用方法。
path函式簽名如下:
path(route,view,name=None,kwargs=None)
route 引數: url 的匹配規則。這個引數中可以指定 url 中需要傳遞的引數,比如在訪問文章詳情頁的時候,可以傳遞一個 id 。傳遞引數是通過 <> 尖括號來進行指定的。並且在傳遞引數的時候,可以指定這個引數的資料型別,比如文章的 id 都是 int 型別,那麼可以這樣寫 <int:id> ,以後匹配的時候,就只會匹配到 id 為 int 型別的 url ,而不會匹配其他的 url ,並且在檢視函式中獲取這個引數的時候,就已經被轉換成一個 int 型別了。
其中還有幾種常用的轉換器型別:
1.str:非空的字串型別。預設的轉換器。但是不能包含斜槓。
2.int:匹配任意的零或者正數的×××。到檢視函式中就是一個int型別。
3.slug:由英文中的橫槓 - ,或者下劃線 _ 連線英文字元或者數字而成的字串。
4.uuid:匹配 uuid 字串。
5.path:匹配非空的英文字串,可以包含斜槓。
Tips:通過from django.urls import converters可以匯入定義轉換器的模組。
下面重點介紹int、str、uuid轉換器,而slug和path轉換器不再解釋。
str轉換器
str轉換器是預設的轉換器,代表如果在引數前面不新增任何東西,那麼將預設採用str轉換器。
在converters模組中對str轉換器的定義如下圖:

其實說白了也就是一個類,然後定義了一個正則表示式,對傳遞的引數進行正則匹配。
int轉換器
在converters模組中對int轉換器的定義如下圖:

從類的定義中可以看出,它是匹配一個0-9的任意一個或多個以上的數字。
uuid轉換器
UUID 是 通用唯一識別碼(Universally Unique Identifier)的縮寫,每個人都可以建立不與其它人衝突的UUID。在這樣的情況下,就不需考慮資料庫建立時的名稱重複問題。目前最廣泛應用的UUID,是微軟公司的全域性唯一識別符號(GUID)。全域性唯一識別符號(GUID,Globally Unique Identifier)是一種由演算法生成的二進位制長度為128位的數字識別符號。GUID的總數達到32^128個,所以隨機生成兩個相同GUID的可能性極小,但並不為0。GUID的格式為:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",其中每個 x 是 0-9 或 a-f 範圍內的一個4位十六進位制數,所以每個x代表4個二進位制位,所以4*32=128個二進位制位,即GUID的總數達到32^128個。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即為有效的 GUID 值。
在converters模組中對uuidt轉換器的定義如下圖:

URL中包含另外一個urls模組
在我們的專案中,不可能只有一個 app ,如果把所有的 app 的 views 中的檢視都放在 first_project專案的urls.py 中進行對映,肯定會讓程式碼顯得非常亂。
就像我們目前的專案一樣顯得十分混亂,多個book的檢視對映都放在一起,如下圖:

因此 django 給我們提供了一個方法,可以在 app 內部包含自己的 url 匹配規則,而在專案的 urls.py 中再統一包含這個 app 的 urls 。使用這個技術需要藉助 include 函式,對include函式的使用後面會有詳細講解,這裡只要知道它的作用即可。
好,現在my_app包裡新增一個urls.py檔案,程式碼修改如下:
from django.urls import path from my_app import views from django.urls import converters urlpatterns = [ path('', views.book_list), path('<int:book_id>/', views.book_detail),# <book_id>就是引數 path('pub/', views.book_pub) ]
然後將first_project專案的urls.py程式碼修改如下:
from django.contrib import admin from django.urls import path,include from my_app import views from django.urls import converters urlpatterns = [ path('admin/', admin.site.urls), path('book/', include("my_app.urls")) ]
從上面兩個檔案程式碼的修改我們可以這樣理解:現在first_project專案的urls.py檔案,將’book/‘原本的對映交給了my_app包裡的urls.py檔案進行內部對映。其實這兩個檔案之間的對映關係就相當於字串的拼接,例如:'book/'拼接my_app的urls.py檔案的'pub/'組合成’book/pub/‘,然後再對映到book_pub檢視函式。
執行結果如下,完全沒有問題,跟分離前一模一樣:
