Django基礎核心技術: URL的設計與配置

Django的URL是如何工作的


URL通常與視圖(View)一起工作的。服務器收到用戶請求後,會根據urls.py裏的關係條目,去視圖View裏查找到與請求對應的處理方法,從而返回給客戶端http頁面數據。這和其它web開發的路由機制(Router)是一個道理。如果你還不知道視圖是什麼,那麼你只需要記住:視圖收到用戶的請求後,展示給用戶看得見的東西


我們來看看下面一個新聞博客的例子:

# blog/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.index),
      path('blog/article/<int:id>/', views.article),
]

# blog/views.py
def index(request):
    # 展示所有文章
    
def article(request, id):
    # 展示某篇具體文章


那麼這段代碼是如何工作的?

  • 當用戶在瀏覽器輸入/blog/時,URL收到請求後會調用視圖views.py裏的index方法,展示所有文章。

  • 當用戶在瀏覽器輸入/blog/article/<int:id>/時,URL不僅調用了views.py裏的article方法,而且還把參數文章id通過<>括號的形式傳遞給了視圖。int這裏代表只傳遞整數,傳遞的參數名字是id。


注意當你配置URL時,別忘了把你的app(比如blog)urls加入項目的URL配置裏(mysite/urls.py), 如下圖所示:

from django.conf.urls import url, include

urlpatterns = [
    url(r'^/', include('blog.urls')),
] 


Django URL傳遞參數的方法path和_re_path


寫個URL很簡單,但如何通過URL把參數傳遞給給視圖view是個技術活。Django URL提供了兩種匹配方式傳遞參數: pathre_path。path是正常參數傳遞,re_path是採用正則表達式regex匹配。path和re_path傳遞參數方式如下:


  • path方法:採用雙尖括號<變量類型:變量名><變量名>傳遞,例如<int:id>, <slug:slug>或<username>。

  • re_path方法: 採用命名組(?P<變量名>表達式)的方式傳遞參數。


下圖兩種傳遞文章id給視圖函數的方式是一樣的。re_path裏引號前面的小寫r表示引號裏爲正則表達式, 請忽略'\'不要轉義,^代表開頭,$代表以結尾,\d+代表正整數。

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [
    path('blog/article/<int:id>/', views.article, name = 'article'),
   re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

# View (in blog/views.py)

def article(request, id):
    # 展示某篇文章


URL的命名及reverse()方法


你注意到沒?我們在上述代碼中還給URL取了一個名字 'article'。這個名字大有用處,相當於給URL取了個全局變量的名字。它可以讓你能夠在Django的任意處,尤其是模板內顯式地引用它。假設你需要在模板中通過鏈接指向一篇具體文章,下面那種方式更好?

方法1: 使用命名URL
<a href="{% url 'article' id %}">Article</a>

方法2: 使用常規URL - 不建議
<a href="blog/article/id">Article</a>


如果你還沒意識到方法1的好處,那麼想想吧,假設你需要把全部模板鏈接由blog/article/id改爲blog/articles/id, 那種方法更快?改所有模板,還是改URL配置裏的一個字母?


可惜的是命名的URL一般只在模板裏使用,不能直接在視圖裏使用。如果我們有了命名的URL,我們如何把它轉化成常規的URL在視圖裏使用呢?Django提供的reverse()方法很容易實現這點。假設不同的app(比如news和blog)裏都有article這個命名URL, 我們怎麼區分呢? 我們只需要在article前面加上blog這個命名空間即可。

from django.urls import reverse

# output blog/article/id
reverse('blog:article', args=[id])


URL如何指向基於類的視圖(View)


目前path和re_path都只能指向視圖view裏的一個函數或方法,而不能指向一個基於類的視圖(Class based view)。Django提供了一個額外as_view()方法,可以將一個類僞裝成方法。這點在當你使用Django在帶的view類或自定義的類時候非常重要。具體使用方式如下:

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [
      path('', views.ArticleList.as_view(), name='article_list'),
    path('blog/article/<int:id>/', views.article, name = 'article'),
    re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

# View (in blog/views.py)
from django.views.generic import ListView
from .views import Article

class ArticleList(ListView):

    queryset = Article.objects.filter(date__lte=timezone.now()).order_by('date')[:5]
    context_object_name = 'latest_article_list'
   template_name = 'blog/article_list.html'

def article(request, id):
    # 展示某篇文章


通過URL方法傳遞額外的參數


在你配置URL時,你還可以通過字典的形式傳遞額外的參數給視圖, 而不用把這個參數寫在鏈接裏。如下面案例所示:

# blog/urls.py
from django.urls import path, re_path

from . import views

urlpatterns = [

    path('', views.ArticleList.as_view(), name='article_list', {'blog_id': 3}),
    re_path(r'^blog/article/(?P<id>\d+)/$', views.article, name='article'),
]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章