1. 程式人生 > >談談Python之Django搭建企業級官網(第三篇上部)

談談Python之Django搭建企業級官網(第三篇上部)

則表達式 oss 不能 目的 SHH oba 解釋 合成 %s

轉載請註明來源地址和原作者(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,是 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視圖函數。

運行結果如下,完全沒有問題,跟分離前一模一樣:
技術分享圖片

Path函數

前面只是簡單了解path函數的使用,現在詳細學習該函數。
path 函數的定義為:

path(route,view,name=None,kwargs=None)  。

以下對這幾個參數進行講解。

  1. route 參數: url 的匹配規則。這個參數中可以指定 url 中需要傳遞的參數,前面已講解,這個參數不再贅述。
  2. view 參數:可以為一個視圖函數或者是 類視圖.as_view() 或者是 django.urls.include() 函數的返回值。
  3. name 參數:這個參數是給這個 url 取個名字的,這在項目比較大, url 比較多的時候用處很大。
  4. kwargs 參數:有時候想給視圖函數傳遞一些額外的參數,就可以通過 kwargs 參數進行傳遞。這個參數接收一個字典。會將foo=bar作為關鍵字實參傳入視圖函數,所以視圖函數要有形參來接收實參。
    比如以下的 url 規則:
    from django.urls import path
    from . import views
    urlpatterns = [
        path(‘blog/<int:year>/‘, views.year_archive, kwargs={‘foo‘:‘bar‘}),  
    ]

    那麽以後在訪問 blog/1991/ 這個url的時候,會將{‘foo‘:‘bar‘}作為關鍵字參數傳給 year_archive函數。year_archive視圖函數的形參中最後添加一個kwargs參數來接收這個額外的參數。

談談Python之Django搭建企業級官網(第三篇上部)