URL 調度器

乾淨、優雅的 URL 方案是高品質 Web 應用程式的重要細節。 Django 讓您可以隨心所欲地設計 URL,沒有框架限制。

請參閱 World Wide Web 創始人 Tim Berners-Lee 的酷炫 URI 不會改變,其中提供了關於為何 URL 應該乾淨且可用的絕佳論點。

概觀

要為應用程式設計 URL,您需要建立一個非正式地稱為 URLconf(URL 設定)的 Python 模組。此模組是純 Python 程式碼,是 URL 路徑表達式到 Python 函數(您的視圖)之間的映射。

此映射可以根據需要而長或短。它可以參考其他映射。而且,由於它是純 Python 程式碼,因此可以動態建構。

Django 還提供了一種根據活動語言翻譯 URL 的方法。有關更多資訊,請參閱國際化文件

Django 如何處理請求

當使用者從您的 Django 驅動網站請求頁面時,系統會遵循此演算法來決定要執行哪個 Python 程式碼

  1. Django 會決定要使用的根 URLconf 模組。通常,這是ROOT_URLCONF 設定的值,但是如果傳入的 HttpRequest 物件具有 urlconf 屬性(由中介軟體設定),則其值將取代ROOT_URLCONF 設定。

  2. Django 會載入該 Python 模組,並尋找變數 urlpatterns。這應該是 序列django.urls.path() 和/或 django.urls.re_path() 實例。

  3. Django 會依序執行每個 URL 模式,並在第一個與請求的 URL 相符的模式處停止,並與path_info 進行比對。

  4. 一旦其中一個 URL 模式匹配,Django 會匯入並呼叫指定的視圖,該視圖是一個 Python 函數(或基於類的視圖)。視圖會傳遞以下引數

    • HttpRequest 的實例。

    • 如果匹配的 URL 模式不包含具名群組,則正規表示式中的匹配項將作為位置引數提供。

    • 關鍵字引數由路徑表達式中匹配的任何具名部分組成,並由django.urls.path()django.urls.re_path() 的可選 kwargs 引數中指定的任何引數覆寫。

  5. 如果沒有 URL 模式匹配,或者在此過程中的任何點引發例外,Django 將會呼叫適當的錯誤處理視圖。請參閱下方的錯誤處理

範例

以下是一個範例 URLconf

from django.urls import path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<int:year>/", views.year_archive),
    path("articles/<int:year>/<int:month>/", views.month_archive),
    path("articles/<int:year>/<int:month>/<slug:slug>/", views.article_detail),
]

注意事項

  • 若要從 URL 擷取值,請使用角括號。

  • 擷取的值可以選擇性地包含轉換器類型。例如,使用 <int:name> 擷取整數參數。如果未包含轉換器,則會比對任何字串(不包括 / 字元)。

  • 無需新增前導斜線,因為每個 URL 都有前導斜線。例如,它是 articles,而不是 /articles

範例請求

  • /articles/2005/03/ 的請求會比對列表中的第三個項目。Django 會呼叫函數 views.month_archive(request, year=2005, month=3)

  • /articles/2003/ 會比對列表中的第一個模式,而不是第二個模式,因為模式是依序測試的,而第一個模式是第一個通過測試的模式。您可以自由利用排序來插入像這樣的特殊案例。在這裡,Django 會呼叫函數 views.special_case_2003(request)

  • /articles/2003 不會比對任何這些模式,因為每個模式都要求 URL 以斜線結尾。

  • /articles/2003/03/building-a-django-site/ 會比對最後一個模式。Django 會呼叫函數 views.article_detail(request, year=2003, month=3, slug="building-a-django-site")

路徑轉換器

預設情況下,可以使用以下路徑轉換器

  • str - 比對任何非空字串,但不包括路徑分隔符號 '/'。如果表達式中未包含轉換器,則此為預設值。

  • int - 比對零或任何正整數。傳回 int

  • slug - 比對由 ASCII 字母或數字,以及連字號和底線字元組成的任何 slug 字串。例如,building-your-1st-django-site

  • uuid - 比對格式化的 UUID。為防止多個 URL 映射到同一個頁面,必須包含破折號,並且字母必須是小寫字母。例如,075194d3-6885-417e-a8a8-6c931e272f00。傳回 UUID 實例。

  • path - 比對任何非空字串,包括路徑分隔符號 '/'。這可讓您比對完整的 URL 路徑,而不是像 str 一樣的 URL 路徑的片段。

註冊自訂路徑轉換器

針對更複雜的匹配需求,您可以定義自己的路徑轉換器。

轉換器是一個包含以下內容的類別

  • 作為字串的 regex 類別屬性。

  • to_python(self, value) 方法,用於處理將匹配的字串轉換為應傳遞至視圖函數的類型。如果無法轉換給定的值,則應引發 ValueErrorValueError 會被解釋為不匹配,因此,除非另一個 URL 模式匹配,否則會將 404 回應傳送給使用者。

  • to_url(self, value) 方法,用於處理將 Python 類型轉換為要在 URL 中使用的字串。如果無法轉換給定的值,則應引發 ValueErrorValueError 會被解釋為不匹配,因此,除非另一個 URL 模式匹配,否則reverse() 會引發 NoReverseMatch

例如

class FourDigitYearConverter:
    regex = "[0-9]{4}"

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return "%04d" % value

使用 register_converter() 在您的 URLconf 中註冊自訂轉換器類別

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, "yyyy")

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<yyyy:year>/", views.year_archive),
    ...,
]

自 5.1 版起已棄用:不建議使用 django.urls.register_converter() 覆寫現有的轉換器。

使用正規表示式

如果路徑和轉換器語法不足以定義您的 URL 模式,您也可以使用正規表示式。若要這樣做,請使用re_path() 而不是path()

在 Python 正規表示式中,具名正規表示式群組的語法為 (?P<name>pattern),其中 name 是群組的名稱,而 pattern 是要比對的某些模式。

以下是先前使用正規表示式重寫的範例 URLconf

from django.urls import path, re_path

from . import views

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

這大致完成了與先前範例相同的操作,除了

  • 將匹配的確切 URL 略為受限。例如,年份 10000 將不再匹配,因為年份整數被限制為正好四位數字。

  • 無論正規表示式進行哪種比對,每個擷取的引數都會以字串的形式傳送至視圖。

從使用 path() 切換到 re_path() 或反之亦然時,特別要注意視圖引數的類型可能會變更,因此您可能需要調整視圖。

使用未具名的正規表示式群組

除了具名群組語法,例如 (?P<year>[0-9]{4}),您也可以使用較短的未命名群組,例如 ([0-9]{4})

這種用法不太建議,因為它更容易在比對的預期含義和檢視的引數之間意外引入錯誤。

在任何情況下,建議在給定的正規表示式中僅使用一種樣式。當兩種樣式混合使用時,任何未命名的群組都會被忽略,只有命名的群組會傳遞到檢視函式。

巢狀引數

正規表示式允許巢狀引數,而 Django 會解析它們並將它們傳遞到檢視。在反向解析時,Django 會嘗試填入所有外部捕獲的引數,並忽略任何巢狀捕獲的引數。考慮以下可選地接收頁面引數的 URL 模式

from django.urls import re_path

urlpatterns = [
    re_path(r"^blog/(page-([0-9]+)/)?$", blog_articles),  # bad
    re_path(r"^comments/(?:page-(?P<page_number>[0-9]+)/)?$", comments),  # good
]

這兩種模式都使用巢狀引數,並且會解析:例如,blog/page-2/ 將比對到具有兩個位置引數的 blog_articlespage-2/2comments 的第二種模式會比對到 comments/page-2/,且關鍵字引數 page_number 設定為 2。在這種情況下,外部引數是非捕獲引數 (?:...)

blog_articles 檢視需要反向解析最外部捕獲的引數 page-2/,或者在這種情況下沒有引數,而 comments 可以反向解析,無論有沒有 page_number 的值。

巢狀捕獲的引數會在檢視引數和 URL 之間建立強烈的耦合,如 blog_articles 所示:檢視接收 URL 的一部分 (page-2/) ,而不是只有檢視感興趣的值。當反向解析時,這種耦合更為明顯,因為要反向解析檢視,我們需要傳遞 URL 的片段,而不是頁碼。

一般而言,僅捕獲檢視需要使用的值,並且當正規表示式需要引數但檢視忽略它時,使用非捕獲引數。

URLconf 搜尋的對象

URLconf 會針對請求的 URL 進行搜尋,將其視為一般的 Python 字串。這不包含 GET 或 POST 參數,或是網域名稱。

例如,在對 https://www.example.com/myapp/ 的請求中,URLconf 將會搜尋 myapp/

在對 https://www.example.com/myapp/?page=3 的請求中,URLconf 將會搜尋 myapp/

URLconf 不會查看請求方法。換句話說,所有請求方法 – POSTGETHEAD 等 – 都會將相同的 URL 路由到相同的函式。

為檢視引數指定預設值

一個方便的技巧是為檢視的引數指定預設參數。以下是一個 URLconf 和檢視的範例

# URLconf
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.
    ...

在上面的範例中,兩個 URL 模式都指向相同的檢視 – views.page – 但第一個模式不會從 URL 中捕獲任何內容。如果第一個模式比對,page() 函式將會為 num 使用其預設引數 1。如果第二個模式比對,page() 將會使用捕獲到的任何 num 值。

效能

Django 會處理 urlpatterns 清單中的正規表示式,該清單會在第一次存取時編譯。後續的請求會透過 URL 解析器使用快取的組態。

urlpatterns 變數的語法

urlpatterns 應該是 sequencepath() 和/或 re_path() 執行個體。

錯誤處理

當 Django 無法找到請求 URL 的比對,或者當發生例外時,Django 會調用錯誤處理檢視。

這些情況要使用的檢視由四個變數指定。它們的預設值應該足以應付大多數專案,但可以透過覆寫其預設值來進行進一步的自訂。

如需完整詳細資訊,請參閱關於 自訂錯誤檢視 的文件。

這些值可以在根 URLconf 中設定。在任何其他 URLconf 中設定這些變數都將不起作用。

值必須是可呼叫的,或者是以字串形式表示應調用以處理當前錯誤狀況的檢視的完整 Python 導入路徑。

變數如下

包含其他 URLconf

在任何時候,您的 urlpatterns 都可以「包含」其他 URLconf 模組。這基本上會將一組 URL「紮根」在其他 URL 之下。

例如,以下是 Django 網站本身的 URLconf 的摘錄。它包含了許多其他 URLconf

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path("community/", include("aggregator.urls")),
    path("contact/", include("contact.urls")),
    # ... snip ...
]

每當 Django 遇到 include() 時,它會切斷 URL 中到該點為止比對到的任何部分,並將剩餘的字串傳送到包含的 URLconf 進行進一步處理。

另一種可能性是使用 path() 執行個體的清單來包含其他 URL 模式。例如,考慮此 URLconf

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path("reports/", credit_views.report),
    path("reports/<int:id>/", credit_views.report),
    path("charge/", credit_views.charge),
]

urlpatterns = [
    path("", main_views.homepage),
    path("help/", include("apps.help.urls")),
    path("credit/", include(extra_patterns)),
]

在此範例中,/credit/reports/ URL 將由 credit_views.report() Django 檢視處理。

這可用於從重複使用單一模式前綴的 URLconf 中消除多餘的部分。例如,考慮此 URLconf

from django.urls import path
from . import views

urlpatterns = [
    path("<page_slug>-<page_id>/history/", views.history),
    path("<page_slug>-<page_id>/edit/", views.edit),
    path("<page_slug>-<page_id>/discuss/", views.discuss),
    path("<page_slug>-<page_id>/permissions/", views.permissions),
]

我們可以透過只聲明一次通用路徑前綴並將不同的後綴分組來改進這一點

from django.urls import include, path
from . import views

urlpatterns = [
    path(
        "<page_slug>-<page_id>/",
        include(
            [
                path("history/", views.history),
                path("edit/", views.edit),
                path("discuss/", views.discuss),
                path("permissions/", views.permissions),
            ]
        ),
    ),
]

捕獲的參數

包含的 URLconf 會收到來自父 URLconf 的任何捕獲的參數,因此以下範例是有效的

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path("<username>/blog/", include("foo.urls.blog")),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.blog.index),
    path("archive/", views.blog.archive),
]

在上面的範例中,捕獲的 "username" 變數會如預期傳遞到包含的 URLconf。

將額外選項傳遞給檢視函式

URLconf 有一個勾點,可讓您以 Python 字典的形式將額外的引數傳遞給檢視函式。

path() 函式可以採用可選的第三個引數,該引數應為要傳遞給檢視函式的額外關鍵字引數的字典。

例如

from django.urls import path
from . import views

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

在此範例中,對於 /blog/2005/ 的請求,Django 將會呼叫 views.year_archive(request, year=2005, foo='bar')

此技巧用於 聯合內容框架 中,以將中繼資料和選項傳遞給檢視。

處理衝突

URL 模式可能會捕獲具名關鍵字引數,並且還會在額外引數字典中傳遞具有相同名稱的引數。當這種情況發生時,字典中的引數將會被使用,而不是 URL 中捕獲的引數。

將額外選項傳遞給 include()

同樣地,您可以將額外選項傳遞給 include(),並且包含的 URLconf 中的每一行都會被傳遞額外選項。

例如,以下兩組 URLconf 在功能上是相同的

第一組

# main.py
from django.urls import include, path

urlpatterns = [
    path("blog/", include("inner"), {"blog_id": 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path("archive/", views.archive),
    path("about/", views.about),
]

第二組

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path("blog/", include("inner")),
]

# inner.py
from django.urls import path

urlpatterns = [
    path("archive/", views.archive, {"blog_id": 3}),
    path("about/", views.about, {"blog_id": 3}),
]

請注意,額外選項將會總是傳遞給包含的 URLconf 中的每一行,無論該行的檢視是否實際上接受這些選項作為有效的選項。因此,只有當您確定包含的 URLconf 中的每個檢視都接受您傳遞的額外選項時,此技巧才有用。

反向解析 URL

在 Django 專案中工作時,一個常見的需求是能夠以最終形式取得 URL,無論是為了嵌入在產生的內容中 (檢視和資源 URL、向使用者顯示的 URL 等),或是為了處理伺服器端的導覽流程 (重新導向等)

強烈建議避免硬式編碼這些 URL (這是一種費力、不可擴展且容易出錯的策略)。同樣危險的是設計特設機制來產生與 URLconf 所描述的設計平行的 URL,這可能會導致產生隨著時間推移而過時的 URL。

換句話說,需要的是一種 DRY 機制。在其他優點中,它允許 URL 設計的發展,而不必查看所有專案原始碼來搜尋和取代過時的 URL。

我們能用來取得 URL 的主要資訊是負責處理該 URL 的視圖的識別資訊(例如名稱)。其他必須參與查找正確 URL 的資訊包括視圖參數的類型(位置、關鍵字)和值。

Django 提供了一個解決方案,讓 URL 對應器成為 URL 設計的唯一儲存庫。您將 URLconf 提供給它,然後它就可以雙向使用。

  • 從使用者/瀏覽器請求的 URL 開始,它會呼叫正確的 Django 視圖,並提供從 URL 提取的任何參數及其值。

  • 從對應的 Django 視圖的識別資訊,加上將傳遞給它的參數值開始,取得相關聯的 URL。

第一個是我們在前面章節中討論的用法。第二個稱為 URL 的反向解析反向 URL 比對反向 URL 查詢,或簡稱為 URL 反轉

Django 提供了執行 URL 反轉的工具,這些工具與需要 URL 的不同層級相符。

  • 在範本中:使用 url 範本標籤。

  • 在 Python 程式碼中:使用 reverse() 函式。

  • 在與 Django 模型實例的 URL 處理相關的較高層級程式碼中:get_absolute_url() 方法。

範例

再次考慮這個 URLconf 條目

from django.urls import path

from . import views

urlpatterns = [
    # ...
    path("articles/<int:year>/", views.year_archive, name="news-year-archive"),
    # ...
]

根據此設計,對應於年份 nnnn 的歸檔 URL 為 /articles/<nnnn>/

您可以使用以下方式在範本程式碼中取得這些資訊

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

或在 Python 程式碼中

from django.http import HttpResponseRedirect
from django.urls import reverse


def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse("news-year-archive", args=(year,)))

如果由於某些原因,決定變更發佈年度文章歸檔內容的 URL,那麼您只需要變更 URLconf 中的條目即可。

在某些視圖本質上是通用的情況下,URL 和視圖之間可能存在多對一的關係。對於這些情況,當要反轉 URL 時,視圖名稱不足以作為識別資訊。請閱讀下一節,了解 Django 為此提供的解決方案。

命名 URL 模式

為了執行 URL 反轉,您需要使用已命名的 URL 模式,如上面的範例所示。用於 URL 名稱的字串可以包含您喜歡的任何字元。您不限於有效的 Python 名稱。

命名 URL 模式時,請選擇不太可能與其他應用程式的名稱選擇衝突的名稱。如果您將您的 URL 模式命名為 comment,而另一個應用程式也做了相同的事情,那麼 reverse() 找到的 URL 取決於您的專案 urlpatterns 清單中最後一個模式。

在您的 URL 名稱上加上前綴,可能來自應用程式名稱(例如 myapp-comment 而不是 comment),可以減少衝突的機會。

如果您想要覆寫視圖,您可以刻意選擇與另一個應用程式相同的 URL 名稱。例如,一個常見的用例是覆寫 LoginView。Django 的某些部分和大多數第三方應用程式都假設此視圖具有一個名稱為 login 的 URL 模式。如果您有一個自訂的登入視圖,並將其 URL 命名為 login,只要它在包含 django.contrib.auth.urls(如果有的話)之後的 urlpatterns 中,reverse() 就會找到您的自訂視圖。

如果多個 URL 模式的參數不同,您也可以為它們使用相同的名稱。除了 URL 名稱之外,reverse() 還會比對參數的數量和關鍵字參數的名稱。路徑轉換器也可以引發 ValueError 以表示不符合,詳細資訊請參閱 註冊自訂路徑轉換器

URL 命名空間

簡介

URL 命名空間允許您唯一地反轉已命名的 URL 模式,即使不同的應用程式使用相同的 URL 名稱也是如此。對於第三方應用程式來說,始終使用命名空間的 URL 是一種很好的做法(就像我們在教學課程中所做的那樣)。同樣地,如果部署了應用程式的多個實例,它也允許您反轉 URL。換句話說,由於單一應用程式的多個實例將共用已命名的 URL,因此命名空間提供了一種區分這些已命名 URL 的方法。

正確使用 URL 命名空間的 Django 應用程式可以針對特定的網站部署多次。例如,django.contrib.admin 有一個 AdminSite 類別,允許您部署管理站點的多個實例。在稍後的範例中,我們將討論在兩個不同的位置部署教學課程中的投票應用程式的想法,以便我們可以為兩個不同的受眾(作者和發行商)提供相同的功能。

URL 命名空間由兩個部分組成,這兩個部分都是字串。

應用程式命名空間

這描述了正在部署的應用程式的名稱。單一應用程式的每個實例都將具有相同的應用程式命名空間。例如,Django 的管理應用程式具有可預測的應用程式命名空間 'admin'

實例命名空間

這識別了應用程式的特定實例。實例命名空間在您的整個專案中應是唯一的。但是,實例命名空間可以與應用程式命名空間相同。這用於指定應用程式的預設實例。例如,預設的 Django 管理實例的實例命名空間為 'admin'

命名空間的 URL 是使用 ':' 運算子指定的。例如,管理應用程式的主要索引頁面是使用 'admin:index' 參照的。這表示命名空間為 'admin',已命名的 URL 為 'index'

命名空間也可以巢狀。已命名的 URL 'sports:polls:index' 將在本身定義於頂層命名空間 'sports' 內的命名空間 'polls' 中尋找名為 'index' 的模式。

反轉命名空間的 URL

當給定要解析的命名空間 URL(例如 'polls:index')時,Django 會將完整名稱分成幾個部分,然後嘗試以下查找

  1. 首先,Django 會尋找符合的應用程式命名空間(在此範例中為 'polls')。這將產生該應用程式的實例清單。

  2. 如果有定義目前的應用程式,Django 會尋找並傳回該實例的 URL 解析器。可以使用 reverse() 函式的 current_app 引數指定目前的應用程式。

    url 範本標籤會將目前解析的視圖的命名空間用作 RequestContext 中的目前應用程式。您可以透過設定 request.current_app 屬性上的目前應用程式來覆寫此預設值。

  3. 如果沒有目前的應用程式,Django 會尋找預設的應用程式實例。預設的應用程式實例是具有與應用程式命名空間相符的實例命名空間的實例(在此範例中,是名為 'polls'polls 實例)。

  4. 如果沒有預設的應用程式實例,Django 將選擇該應用程式的最後部署實例,無論其 實例名稱為何。

  5. 如果提供的命名空間在步驟 1 中不符合應用程式命名空間,Django 將嘗試將該命名空間直接查找為實例命名空間

如果有巢狀的命名空間,則會針對命名空間的每個部分重複這些步驟,直到只有視圖名稱未解析。然後,視圖名稱將在已找到的命名空間中解析為 URL。

範例

為了展示此解析策略的作用,請考慮一個教學課程中 polls 應用程式的兩個實例的範例:一個名為 'author-polls',另一個名為 'publisher-polls'。假設我們已增強該應用程式,使其在建立和顯示投票時會將實例命名空間納入考量。

urls.py
from django.urls import include, path

urlpatterns = [
    path("author-polls/", include("polls.urls", namespace="author-polls")),
    path("publisher-polls/", include("polls.urls", namespace="publisher-polls")),
]
polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]

使用此設定,可以進行以下查找

  • 如果其中一個實例是目前的實例 — 比如說,如果我們是在 'author-polls' 這個實例中呈現詳細頁面 — 'polls:index' 將會解析到 'author-polls' 實例的索引頁面;也就是說,以下兩種情況都會產生 "/author-polls/"

    在基於類別的視圖的方法中

    reverse("polls:index", current_app=self.request.resolver_match.namespace)
    

    以及在模板中

    {% url 'polls:index' %}
    
  • 如果沒有目前的實例 — 比如說,如果我們在網站的其他地方呈現頁面 — 'polls:index' 將會解析到最後註冊的 polls 實例。由於沒有預設實例('polls' 的實例命名空間),將會使用最後註冊的 polls 實例。這會是 'publisher-polls',因為它在 urlpatterns 中是最後宣告的。

  • 'author-polls:index' 將始終解析到 'author-polls' 實例的索引頁面('publisher-polls' 也是如此)。

如果還有一個預設實例 — 也就是說,一個名為 'polls' 的實例 — 與上述情況唯一的不同之處會在於沒有目前實例的情況(上述列表中的第二項)。在這種情況下,'polls:index' 會解析到預設實例的索引頁面,而不是 urlpatterns 中最後宣告的實例。

URL 命名空間和包含的 URL 設定

包含的 URL 設定的應用程式命名空間可以用兩種方式指定。

首先,您可以在包含的 URL 設定模組中設定一個 app_name 屬性,與 urlpatterns 屬性位於同一層級。您必須將實際的模組,或是模組的字串引用傳遞給 include(),而不是 urlpatterns 本身的清單。

polls/urls.py
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.IndexView.as_view(), name="index"),
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ...,
]
urls.py
from django.urls import include, path

urlpatterns = [
    path("polls/", include("polls.urls")),
]

polls.urls 中定義的 URL 將會有一個應用程式命名空間 polls

其次,您可以包含一個包含嵌入式命名空間資料的物件。如果您 include() 一個 path()re_path() 實例的清單,則該物件中包含的 URL 將會被新增至全域命名空間。然而,您也可以 include() 一個包含以下內容的 2 元組:

(<list of path()/re_path() instances>, <application namespace>)

例如

from django.urls import include, path

from . import views

polls_patterns = (
    [
        path("", views.IndexView.as_view(), name="index"),
        path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ],
    "polls",
)

urlpatterns = [
    path("polls/", include(polls_patterns)),
]

這會將指定的 URL 模式包含到給定的應用程式命名空間中。

可以使用 include()namespace 參數來指定實例命名空間。如果沒有指定實例命名空間,它將預設為包含的 URL 設定的應用程式命名空間。這表示它也會是該命名空間的預設實例。

返回頂部