Django2.+ path配置


2017年12月2號,Django2.0發布!!!所以之前1.8版本的已經有所改變。

其中url變成path。

 

9月23日Django發布了2.0a1版本,這是一個 feature freeze 版本,如果沒有什么意外的話,2.0正式版不會再增加新的功能了。按照以往的規律,預計正式版將在12月發布。

2.0無疑是一個里程碑版本,因為這是第一個只支持Python3.X的版本,和1.x是不兼容的。

What’s new in Django2.0 文檔中一共列出了三個新的特性:

  • 更簡單的URL路由語法 (Simplified URL routing syntax)
  • admin應用的針對移動設備的優化改進(Mobile-friendly contrib.admin)
  • 支持SQL開窗表達式(Window expressions)

第一個特性,主要用於動態路由定義上。在Django2.0代碼實現中,主要的變化是新增了 django.urls.path 函數,它允許使用一種更加簡潔、可讀的路由語法。比如之前的版本的代碼:

[python]  view plain  copy
 
 
  1. url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),  


新語法支持類型轉化,在上述的例子中, year_archive函數接收到的year參數就變成整數而不是字符串。在新版本中也可以寫為:

如果你有接觸過 Flask 框架,就會發現和 Variable-Rules 的語法形式和功能都是相類似的。

問題引入

下面是Django1.X的一段代碼:

[python]  view plain  copy
 
 
  1. from django.conf.urls import url    
  2. def year_archive(request, year):    
  3.     year = int(year) # convert str to int    
  4.     # Get articles from database    
  5. def detail_view(request, article_id):    
  6.     pass    
  7. def edit_view(request, article_id):    
  8.     pass    
  9. def delete_view(request, article_id):    
  10.     pass    
  11. urlpatterns = [    
  12.     url('articles/(?P<year>[0-9]{4})/', year_archive),    
  13.     url('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),    
  14.     url('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),    
  15.     url('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),    
  16. ]    


考慮下這樣的兩個問題:

第一個問題,函數 year_archive 中year參數是字符串類型的,因此需要先轉化為整數類型的變量值,當然year=int(year) 不會有諸如如TypeError或者ValueError的異常。那么有沒有一種方法,在url中,使得這一轉化步驟可以由Django自動完成?

第二個問題,三個路由中article_id都是同樣的正則表達式,但是你需要寫三遍,當之后article_id規則改變后,需要同時修改三處代碼,那么有沒有一種方法,只需修改一處即可?

在Django2.0中,可以使用 path 解決以上的兩個問題。

基本示例

這是一個簡單的例子:

[python]  view plain  copy
 
 
  1. from django.urls import path    
  2. from . import views    
  3. urlpatterns = [    
  4.     path('articles/2003/', views.special_case_2003),    
  5.     path('articles/<int:year>/', views.year_archive),    
  6.     path('articles/<int:year>/<int:month>/', views.month_archive),    
  7.     path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),    
  8. ]    

基本規則:

  • 使用尖括號(<>)從url中捕獲值。
  • 捕獲值中可以包含一個轉化器類型(converter type),比如使用 <int:name> 捕獲一個整數變量。若果沒有轉化器,將匹配任何字符串,當然也包括了 / 字符。
  • 無需添加前導斜杠。

以下是根據 2.0官方文檔 而整理的示例分析表:

請求URL 匹配項 視圖函數調用形式
/articles/2005/03/ 第3個 views.month_archive(request, year=2005, month=3)
/articles/2003/ 第1個 views.special_case_2003(request)
/articles/2003 -
/articles/2003/03/building-a-django-site/ 第4個 views.article_detail(request, year=2003, month=3, slug=”building-a-django-site”)

path轉化器

文檔原文是Path converters,暫且翻譯為轉化器。

Django默認支持以下5個轉化器:

  • str,匹配除了路徑分隔符(/)之外的非空字符串,這是默認的形式
  • int,匹配正整數,包含0。
  • slug,匹配字母、數字以及橫杠、下划線組成的字符串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字符串,包含了路徑分隔符

注冊自定義轉化器

對於一些復雜或者復用的需要,可以定義自己的轉化器。轉化器是一個類或接口,它的要求有三點:

  • regex 類屬性,字符串類型

  • to_python(self, value) 方法,value是由類屬性 regex 所匹配到的字符串,返回具體的Python變量值,以供Django傳遞到對應的視圖函數中。

  • to_url(self, value) 方法,和 to_python 相反,value是一個具體的Python變量值,返回其字符串,通常用於url反向引用。

例子:

[python]  view plain  copy
 
 
  1. class FourDigitYearConverter:    
  2.     regex = '[0-9]{4}'    
  3.     def to_python(self, value):    
  4.         return int(value)    
  5.     def to_url(self, value):    
  6.         return '%04d' % value    

使用register_converter 將其注冊到URL配置中:

[python]  view plain  copy
 
 
  1. from django.urls import register_converter, path    
  2. from . import converters, views    
  3. register_converter(converters.FourDigitYearConverter, 'yyyy')    
  4. urlpatterns = [    
  5.     path('articles/2003/', views.special_case_2003),    
  6.     path('articles/<yyyy:year>/', views.year_archive),    
  7.     ...    
  8. ]    

使用正則表達式

如果上述的paths和converters還是無法滿足需求,也可以使用正則表達式,這時應當使用 django.urls.re_path函數。

在Python正則表達式中,命名式分組語法為 (?P<name>pattern) ,其中name為名稱, pattern為待匹配的模式。

之前的示例代碼也可以寫為:

[python]  view plain  copy
 
 
  1. from django.urls import path, re_path    
  2. from . import views    
  3. urlpatterns = [    
  4.     path('articles/2003/', views.special_case_2003),    
  5.     re_path('articles/(?P<year>[0-9]{4})/', views.year_archive),    
  6.     re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_archive),    
  7.     re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[^/]+)/', views.article_detail),    
  8. ]    

這段代碼和之前的代碼實現了基本的功能,但是還是有一些區別:

  • 這里的代碼匹配更加嚴格,比如year=10000在這里就無法匹配。
  • 傳遞給視圖函數的變量都是字符串類型,這點和 url 是一致的。

無命名分組

一般來說,不建議使用這種方式,因為有可能引入歧義,甚至錯誤。

Import變動

django.urls.path 可以看成是 django.conf.urls.url 的增強形式。

為了方便,其引用路徑也有所變化。

1.X 2.0 備注
- django.urls.path 新增,url的增強版
django.conf.urls.include django.urls.include 路徑變更
django.conf.urls.url django.urls.re_path 異名同功能,url不會立即廢棄

總結

新的path語法可以解決一下以下幾個場景:

  • 類型自動轉化
  • 公用正則表達式

將問題引入一節的代碼使用新的path函數可以改寫如下:

[python]  view plain  copy
 
 
  1. from django.urls import path, register_converter    
  2. class ArticleIdConverter:    
  3.     regex = '[a-zA-Z0-9]+'    
  4.     def to_python(self, value):    
  5.         return value    
  6.     def to_url(self, value):    
  7.         return value    
  8. register_converter(ArticleIdConverter, 'article_id')    
  9. def year_archive(request, year):    
  10.     year = int(year) # convert str to int    
  11.     # Get articles from database    
  12. def detail_view(request, article_id):    
  13.     pass    
  14. def edit_view(request, article_id):    
  15.     pass    
  16. def delete_view(request, article_id):    
  17.     pass    
  18. urlpatterns = [    
  19.     url('articles/(?P<year>[0-9]{4})/', year_archive),    
  20.     url('article/<article_id:article_id>/detail/', detail_view),    
  21.     url('articles/<article_id:article_id>/edit/', edit_view),    
  22.     url('articles/<article_id:article_id>/delete/', delete_view),    
  23. ]    

從流程來看,包含了四個步驟:匹配 => 捕獲 => 轉化 => 視圖調用,和之前相比多了轉化這一步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM