0基礎掌握Django框架(6)視圖與URL分發器

URL分發器

為了更好的學習效果,請搭配視頻教程一起學習:

Django零基礎到項目實戰 - 網易雲課堂?

study.163.com

視圖:

視圖一般都寫在appviews.py中。並且視圖的第一個參數永遠都是request(一個HttpRequest)對象。這個對象存儲了請求過來的所有信息,包括攜帶的參數以及一些頭部信息等。在視圖中,一般是完成邏輯相關的操作。比如這個請求是添加一篇博客,那麼可以通過request來接收到這些數據,然後存儲到資料庫中,最後再把執行的結果返回給瀏覽器。視圖函數的返回結果必須是HttpResponseBase對象或者子類的對象。示例代碼如下:

from django.http import HttpResponse
def book_list(request):
return HttpResponse("書籍列表!")

URL映射:

視圖寫完後,要與URL進行映射,也即用戶在瀏覽器中輸入什麼url的時候可以請求到這個視圖函數。在用戶輸入了某個url,請求到我們的網站的時候,django會從項目的urls.py文件中尋找對應的視圖。在urls.py文件中有一個urlpatterns變數,以後django就會從這個變數中讀取所有的匹配規則。匹配規則需要使用django.urls.path函數進行包裹,這個函數會根據傳入的參數返回URLPattern或者是URLResolver的對象。示例代碼如下:

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)
]

URL中添加參數:

有時候,url中包含了一些參數需要動態調整。比如簡書某篇文章的詳情頁的url,是https://www.jianshu.com/p/a5aab9c4978e後面的a5aab9c4978e就是這篇文章的id,那麼簡書的文章詳情頁面的url就可以寫成https://www.jianshu.com/p/<id>,其中id就是文章的id。那麼如何在django中實現這種需求呢。這時候我們可以在path函數中,使用尖括弧的形式來定義一個參數。比如我現在想要獲取一本書籍的詳細信息,那麼應該在url中指定這個參數。示例代碼如下:

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)
]

views.py中的代碼如下:

def book_detail(request,book_id):
text = "您輸入的書籍的id是:%s" % book_id
return HttpResponse(text)

當然,也可以通過查詢字元串的方式傳遞一個參數過去。示例代碼如下:

urlpatterns = [
path(admin/, admin.site.urls),
path(book/,views.book_list),
path(book/detail/,views.book_detail)
]

views.py中的代碼如下:

def book_detail(request):
book_id = request.GET.get("id")
text = "您輸入的書籍id是:%s" % book_id
return HttpResponse(text)

以後在訪問的時候就是通過/book/detail/?id=1即可將參數傳遞過去。

URL中包含另外一個urls模塊:

在我們的項目中,不可能只有一個app,如果把所有的appviews中的視圖都放在urls.py中進行映射,肯定會讓代碼顯得非常亂。因此django給我們提供了一個方法,可以在app內部包含自己的url匹配規則,而在項目的urls.py中再統一包含這個appurls。使用這個技術需要藉助include函數。示例代碼如下:

# first_project/urls.py文件:

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
path(admin/, admin.site.urls),
path(book/,include("book.urls"))
]

urls.py文件中把所有的和book這個app相關的url都移動到app/urls.py中了,然後在first_project/urls.py中,通過include函數包含book.urls,以後在請求book相關的url的時候都需要加一個book的前綴。

# book/urls.py文件:

from django.urls import path
from . import views

urlpatterns = [
path(list/,views.book_list),
path(detail/<book_id>/,views.book_detail)
]

以後訪問書的列表的url的時候,就通過/book/list/來訪問,訪問書籍詳情頁面的url的時候就通過book/detail/<id>來訪問。

path函數:

path函數的定義為:path(route,view,name=None,kwargs=None)。以下對這幾個參數進行講解。

  1. route參數:url的匹配規則。這個參數中可以指定url中需要傳遞的參數,比如在訪問文章詳情頁的時候,可以傳遞一個id。傳遞參數是通過<>尖括弧來進行指定的。並且在傳遞參數的時候,可以指定這個參數的數據類型,比如文章的id都是int類型,那麼可以這樣寫<int:id>,以後匹配的時候,就只會匹配到idint類型的url,而不會匹配其他的url,並且在視圖函數中獲取這個參數的時候,就已經被轉換成一個int類型了。其中還有幾種常用的類型:
  2. str:非空的字元串類型。默認的轉換器。但是不能包含斜杠。
  3. int:匹配任意的零或者正數的整形。到視圖函數中就是一個int類型。
  4. slug:由英文中的橫杠-,或者下劃線_連接英文字元或者數字而成的字元串。
  5. uuid:匹配uuid字元串。
  6. path:匹配非空的英文字元串,可以包含斜杠。
  7. view參數:可以為一個視圖函數或者是類視圖.as_view()或者是django.urls.include()函數的返回值。
  8. name參數:這個參數是給這個url取個名字的,這在項目比較大,url比較多的時候用處很大。
  9. kwargs參數:有時候想給視圖函數傳遞一些額外的參數,就可以通過kwargs參數進行傳遞。這個參數接收一個字典。傳到視圖函數中的時候,會作為一個關鍵字參數傳過去。比如以下的url規則:

from django.urls import path
from . import views
urlpatterns = [
path(blog/<int:year>/, views.year_archive, {foo: bar}),
]

那麼以後在訪問blog/1991/這個url的時候,會將foo=bar作為關鍵字參數傳給year_archive函數。

re_path函數:

有時候我們在寫url匹配的時候,想要寫使用正則表達式來實現一些複雜的需求,那麼這時候我們可以使用re_path來實現。re_path的參數和path參數一模一樣,只不過第一個參數也就是route參數可以為一個正則表達式。

一些使用re_path的示例代碼如下:

from django.urls import path, re_path

from . import views

urlpatterns = [
path(articles/2003/, views.special_case_2003),
re_path(rarticles/(?P<year>[0-9]{4})/, views.year_archive),
re_path(rarticles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/, views.month_archive),
re_path(rarticles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[w-_]+)/, views.article_detail),
]

以上例子中我們可以看到,所有的route字元串前面都加了一個r,表示這個字元串是一個原生字元串。在寫正則表達式中是推薦使用原生字元串的,這樣可以避免在python這一層面進行轉義。而且,使用正則表達式捕獲參數的時候,是用一個圓括弧進行包裹,然後這個參數的名字是通過尖括弧<year>進行包裹,之後才是寫正則表達式的語法。

include函數:

在項目變大以後,經常不會把所有的url匹配規則都放在項目的urls.py文件中,而是每個app都有自己的urls.py文件,在這個文件中存儲的都是當前這個app的所有url匹配規則。然後再統一註冊到項目的urls.py文件中。include函數有多種用法,這裡講下兩種常用的用法。

  1. include(pattern,namespace=None):直接把其他appurls包含進來。示例代碼如下:

from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path(admin/, admin.site.urls),
path(book/,include("book.urls"))
]

當然也可以傳遞namespace參數來指定一個實例命名空間,但是在使用實例命名空間之前,必須先指定一個應用命名空間。示例代碼如下:

# 主urls.py文件:
from django.urls import path,include
urlpatterns = [
path(movie/,include(movie.urls,namespace=movie))
]

然後在movie/urls.py中指定應用命名空間。實例代碼如下:

from django.urls import path
from . import views

# 應用命名空間
app_name = movie
urlpatterns = [
path(,views.movie,name=index),
path(list/,views.movie_list,name=list),
]

  1. include(pattern_list):可以包含一個列表或者一個元組,這個元組或者列表中又包含的是path或者是re_path函數。

  2. include((pattern,app_namespace),namespace=None):在包含某個appurls的時候,可以指定命名空間,這樣做的目的是為了防止不同的app下出現相同的url,這時候就可以通過命名空間進行區分。示例代碼如下:

from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path(admin/, admin.site.urls),
path(book/,include(("book.urls",book)),namespace=book)
]

但是這樣做的前提是已經包含了應用命名空間。即在myapp.urls.py中添加一個和urlpatterns同級別的變數app_name

指定默認的參數:

使用path或者是re_path的後,在route中都可以包含參數,而有時候想指定默認的參數,這時候可以通過以下方式來完成。示例代碼如下:

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/的時候,因為沒有傳遞num參數,所以會匹配到第一個url,這時候就執行view.page這個視圖函數,而在page函數中,又有num=1這個默認參數。因此這時候就可以不用傳遞參數。而如果訪問blog/1的時候,因為在傳遞參數的時候傳遞了num,因此會匹配到第二個url,這時候也會執行views.page,然後把傳遞進來的參數傳給page函數中的num

url反轉:

之前我們都是通過url來訪問視圖函數。有時候我們知道這個視圖函數,但是想反轉回他的url。這時候就可以通過reverse來實現。示例代碼如下:

reverse("list")
> /book/list/

如果有應用命名空間或者有實例命名空間,那麼應該在反轉的時候加上命名空間。示例代碼如下:

reverse(book:list)
> /book/list/

如果這個url中需要傳遞參數,那麼可以通過kwargs來傳遞參數。示例代碼如下:

reverse("book:detail",kwargs={"book_id":1})
> /book/detail/1

因為django中的reverse反轉url的時候不區分GET請求和POST請求,因此不能在反轉的時候添加查詢字元串的參數。如果想要添加查詢字元串的參數,只能手動的添加。示例代碼如下:

login_url = reverse(login) + "?next=/"

自定義URL轉換器:

之前已經學到過一些django內置的url轉換器,包括有intuuid等。有時候這些內置的url轉換器並不能滿足我們的需求,因此django給我們提供了一個介面可以讓我們自己定義自己的url轉換器。

自定義url轉換器按照以下五個步驟來走就可以了:

1. 定義一個類。

2. 在類中定義一個屬性regex,這個屬性是用來保存url轉換器規則的正則表達式。

3. 實現to_python(self,value)方法,這個方法是將url中的值轉換一下,然後傳給視圖函數的。

4. 實現to_url(self,value)方法,這個方法是在做url反轉的時候,將傳進來的參數轉換後拼接成一個正確的url。

5. 將定義好的轉換器,註冊到django中。

比如寫一個匹配四個數字年份的url轉換器。示例代碼如下:

# 1. 定義一個類
class FourDigitYearConverter:
# 2. 定義一個正則表達式
regex = [0-9]{4}

# 3. 定義to_python方法
def to_python(self, value):
return int(value)

# 4. 定義to_url方法
def to_url(self, value):
return %04d % value

# 5. 註冊到django中
from django.urls import register_converter
register_converter(converters.FourDigitYearConverter, yyyy)
urlpatterns = [
path(articles/2003/, views.special_case_2003),
# 使用註冊的轉換器
path(articles/<yyyy:year>/, views.year_archive),
...
]

為了更好的學習效果,請搭配視頻教程一起學習:

Django零基礎到項目實戰 - 網易雲課堂?

study.163.com


推薦閱讀:

TAG:Django(框架) |