Django 處理HTTP請(qǐng)求

2021-10-20 18:24 更新

URL調(diào)度

干凈,優(yōu)雅的URL方案是高質(zhì)量Web應(yīng)用程序中的重要細(xì)節(jié)。Django允許您根據(jù)需要設(shè)計(jì)URL,而無框架限制。

萬維網(wǎng)創(chuàng)建者蒂姆·伯納斯-李(Tim Berners-Lee)的文章“ Cool URIs not not change”中有關(guān)為什么URL應(yīng)該干凈和可用的出色論據(jù),請(qǐng)參見。

概述

要設(shè)計(jì)應(yīng)用程序的URL,您可以創(chuàng)建一個(gè)非正式地稱為URLconf(URL配置)的Python模塊 。該模塊是純Python代碼,并且是URL路徑表達(dá)式到Python函數(shù)(您的視圖)之間的映射。

該映射可以根據(jù)需要短或長(zhǎng)。它可以引用其他映射。而且,由于它是純Python代碼,因此可以動(dòng)態(tài)構(gòu)建。

Django還提供了一種根據(jù)活動(dòng)語(yǔ)言翻譯URL的方法。有關(guān)更多信息,請(qǐng)參見國(guó)際化文檔。

Django是如何處理一個(gè)請(qǐng)求

當(dāng)用戶從您的Django支持的網(wǎng)站請(qǐng)求頁(yè)面時(shí),系統(tǒng)將使用以下算法來確定要執(zhí)行的Python代碼:

  1. Django確定要使用的根URLconf模塊。通常,這是ROOT_URLCONF設(shè)置的值,但是如果傳入 HttpRequest對(duì)象具有urlconf 屬性(由中間件設(shè)置),則將使用其值代替 ROOT_URLCONF設(shè)置。
  2. Django加載該P(yáng)ython模塊并查找變量 urlpatterns。這應(yīng)該是一個(gè)序列的 django.urls.path()和/或django.urls.re_path()實(shí)例。
  3. Django按順序遍歷每個(gè)URL模式,并在第一個(gè)與請(qǐng)求的URL匹配的URL處停止,與匹配 path_info。
  4. 一旦其中一個(gè)URL模式匹配,Django就會(huì)導(dǎo)入并調(diào)用給定的視圖,該視圖是Python函數(shù)(或基于類的視圖)。該視圖將傳遞以下參數(shù):的實(shí)例HttpRequest。如果匹配的URL模式不包含命名組,則來自正則表達(dá)式的匹配項(xiàng)將作為位置參數(shù)提供。關(guān)鍵字參數(shù)由提供的路徑表達(dá)式匹配的任何命名部分組成,這些名稱部分由或 的可選kwargs參數(shù)中指定的任何參數(shù)覆蓋。django.urls.path()django.urls.re_path()在Django 3.0中進(jìn)行了更改:在舊版本中,帶有None值的關(guān)鍵字參數(shù)也由未提供的命名部分組成。
  5. 如果沒有URL模式匹配,或者在此過程中的任何時(shí)候引發(fā)異常,Django都會(huì)調(diào)用一個(gè)適當(dāng)?shù)腻e(cuò)誤處理視圖。請(qǐng)參閱下面的錯(cuò)誤處理。

例子

這是一個(gè)示例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捕獲值,請(qǐng)使用尖括號(hào)。
  • 捕獲的值可以選擇包括轉(zhuǎn)換器類型。例如,用于 `捕獲整數(shù)參數(shù)。如果不包括轉(zhuǎn)換器/`,則匹配除字符以外的任何字符串。
  • 無需添加斜杠,因?yàn)槊總€(gè)URL都有該斜杠。例如articles,不是/articles。

請(qǐng)求示例:

  • 請(qǐng)求/articles/2005/03/匹配列表中的第三個(gè)條目。Django將調(diào)用該函數(shù) 。views.month_archive(request, year=2005, month=3)
  • /articles/2003/會(huì)匹配列表中的第一個(gè)模式,而不是第二個(gè),因?yàn)檫@些模式是按順序測(cè)試的,而第一個(gè)是第一個(gè)通過的測(cè)試。隨意利用命令來插入類似這樣的特殊情況。在這里,Django將調(diào)用該函數(shù) views.special_case_2003(request)
  • /articles/2003 不會(huì)與任何這些模式匹配,因?yàn)槊糠N模式都要求URL以斜杠結(jié)尾。
  • /articles/2003/03/building-a-django-site/將匹配最終模式。Django將調(diào)用該函數(shù) 。views.article_detail(request, year=2003, month=3, slug="building-a-django-site")

路徑轉(zhuǎn)換器

默認(rèn)情況下,以下路徑轉(zhuǎn)換器可用:

  • str-匹配任何非空字符串,但路徑分隔符除外'/'。如果表達(dá)式中不包含轉(zhuǎn)換器,則為默認(rèn)設(shè)置。
  • int-匹配零或任何正整數(shù)。返回int。
  • slug-匹配由ASCII字母或數(shù)字以及連字符和下劃線字符組成的任何條形字符串。例如, building-your-1st-django-site。
  • uuid-匹配格式化的UUID。為防止多個(gè)URL映射到同一頁(yè)面,必須包含破折號(hào),并且字母必須小寫。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一個(gè) UUID實(shí)例。
  • path-匹配任何非空字符串,包括路徑分隔符 '/'。這樣,您就可以匹配完整的URL路徑,而不是像一樣匹配URL路徑的一部分str。

注冊(cè)自定義路徑轉(zhuǎn)換器

對(duì)于更復(fù)雜的匹配要求,您可以定義自己的路徑轉(zhuǎn)換器。

轉(zhuǎn)換器是包含以下內(nèi)容的類:

  • 一regex類屬性,作為一個(gè)字符串。
  • 一種方法,用于將匹配的字符串轉(zhuǎn)換為應(yīng)傳遞給視圖函數(shù)的類型。如果無法轉(zhuǎn)換給定值,則應(yīng)加注。A 被解釋為不匹配,結(jié)果404響應(yīng)會(huì)發(fā)送給用戶,除非另一個(gè)URL模式匹配。to_python(self, value)``ValueError``ValueError
  • 一種方法,用于將Python類型轉(zhuǎn)換為要在URL中使用的字符串。to_url(self, value)

例如:

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中注冊(cè)自定義轉(zhuǎn)換器類 :

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

使用正則表達(dá)式

如果路徑和轉(zhuǎn)換器語(yǔ)法不足以定義URL模式,則還可以使用正則表達(dá)式。為此,請(qǐng)使用 re_path()代替path()

在Python正則表達(dá)式中,命名正則表達(dá)式組的語(yǔ)法為(?Ppattern),其中name是組的名稱,并且 pattern是匹配的某種模式。

這是前面的示例URLconf,使用正則表達(dá)式重寫:

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

這可以完成與上一個(gè)示例大致相同的操作,除了:

  • 將要匹配的確切URL受到更多限制。例如,年份10000將不再匹配,因?yàn)槟攴菡麛?shù)被限制為正好是四位數(shù)長(zhǎng)。
  • 無論正則表達(dá)式進(jìn)行哪種匹配,每個(gè)捕獲的參數(shù)都將作為字符串發(fā)送到視圖。

當(dāng)從使用切換為使用path(), re_path()反之亦然時(shí),特別重要的是要注意視圖參數(shù)的類型可能會(huì)更改,因此您可能需要調(diào)整視圖。

使用未命名的正則表達(dá)式組

除了命名組語(yǔ)法(例如)之外(?P[0-9]{4}),您還可以使用較短的未命名組(例如)([0-9]{4})。

不建議特別使用此用法,因?yàn)檫@樣可以更輕松地在匹配的預(yù)期含義和視圖的參數(shù)之間意外引入錯(cuò)誤。

無論哪種情況,建議在給定的正則表達(dá)式中僅使用一種樣式。當(dāng)兩種樣式混合使用時(shí),任何未命名的組都會(huì)被忽略,只有命名的組才會(huì)傳遞給視圖函數(shù)。

嵌套參數(shù)

正則表達(dá)式允許嵌套參數(shù),而Django會(huì)解析它們并將其傳遞給視圖。反轉(zhuǎn)時(shí),Django將嘗試填寫所有外部捕獲的參數(shù),而忽略任何嵌套的捕獲參數(shù)。考慮以下URL模式,這些URL模式可以選擇采用page參數(shù):

from django.urls import re_path
?
urlpatterns = [
  re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                 # bad
  re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]

兩種模式都使用嵌套參數(shù),并將解析:例如, blog/page-2/將導(dǎo)致與匹配blog_articles兩個(gè)位置參數(shù):page-2/和2。的第二個(gè)模式 comments將comments/page-2/與關(guān)鍵字參數(shù) page_number設(shè)置為2 匹配。在這種情況下,外部參數(shù)是一個(gè)非捕獲參數(shù)(?:...)。

該blog_articles視圖需要最外層捕獲的參數(shù)被反轉(zhuǎn),page-2/或者在這種情況下不需要參數(shù),而視圖 comments可以不帶參數(shù)也沒有值而被反轉(zhuǎn)page_number。

嵌套的捕獲參數(shù)在視圖參數(shù)和URL之間建立了牢固的耦合,如下所示blog_articles:視圖接收部分URL(page-2/),而不是僅接收視圖感興趣的值。這種反轉(zhuǎn)在反轉(zhuǎn)時(shí)更為明顯,因?yàn)榉崔D(zhuǎn)視圖,我們需要傳遞該URL而不是頁(yè)碼。

根據(jù)經(jīng)驗(yàn),當(dāng)正則表達(dá)式需要參數(shù)但視圖將其忽略時(shí),僅捕獲視圖需要使用的值,并使用非捕獲參數(shù)。

URLconf搜索的內(nèi)容

URLconf按照正常的Python字符串搜索請(qǐng)求的URL。這不包括GET或POST參數(shù)或域名。

例如,在對(duì)的請(qǐng)求中https://www.example.com/myapp/,URLconf將尋找myapp/。

在請(qǐng)求中https://www.example.com/myapp/?page=3,URLconf將尋找myapp/。

URLconf不會(huì)查看請(qǐng)求方法。換句話說,所有的請(qǐng)求方法- ,,POST 等-將被路由到相同的URL相同的功能。GET``HEAD

為視圖參數(shù)指定默認(rèn)值

一個(gè)方便的技巧是為視圖的參數(shù)指定默認(rèn)參數(shù)。這是一個(gè)示例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.
  ...

在上面的示例中,兩個(gè)URL模式都指向同一視圖– views.page–但是第一個(gè)模式未從URL中捕獲任何內(nèi)容。如果第一個(gè)模式匹配,該page()函數(shù)將使用它的默認(rèn)參數(shù)num,1。如果第二個(gè)模式匹配, page()將使用num捕獲的任何值。

性能

中的每個(gè)正則表達(dá)式urlpatterns都是在首次訪問時(shí)進(jìn)行編譯。這使系統(tǒng)運(yùn)行起來非常快。

在語(yǔ)法urlpatterns變量

urlpatterns應(yīng)該是一個(gè)序列的path() 和/或re_path()實(shí)例。

錯(cuò)誤處理

當(dāng)Django無法找到所請(qǐng)求URL的匹配項(xiàng)或引發(fā)異常時(shí),Django會(huì)調(diào)用錯(cuò)誤處理視圖。

這些情況下使用的視圖由四個(gè)變量指定。它們的默認(rèn)值足以滿足大多數(shù)項(xiàng)目的需要,但可以通過覆蓋其默認(rèn)值來進(jìn)行進(jìn)一步的自定義。

有關(guān)完整的詳細(xì)信息,請(qǐng)參見有關(guān)自定義錯(cuò)誤視圖的文檔。

可以在您的根URLconf中設(shè)置這些值。在任何其他URLconf中設(shè)置這些變量將無效。

值必須是可調(diào)用的,或者是表示視圖的完整Python導(dǎo)入路徑的字符串,應(yīng)該調(diào)用該視圖來處理當(dāng)前的錯(cuò)誤情況。

變量是:

包括其他的URLconf 

在任何時(shí)候,您urlpatterns都可以“包括”其他URLconf模塊。實(shí)質(zhì)上,這會(huì)將“ URL”“植根”在其他URL之下。

例如,這是Django網(wǎng)站 本身的URLconf的摘錄。它包括許多其他URLconf:

from django.urls import include, path
?
urlpatterns = [
  # ... snip ...
  path('community/', include('aggregator.urls')),
  path('contact/', include('contact.urls')),
  # ... snip ...
]

每當(dāng)Django遇到時(shí)include(),它都會(huì)截?cái)嘀钡皆摃r(shí)間點(diǎn)匹配的URL的任何部分,并將剩余的字符串發(fā)送到包含的URLconf中以進(jìn)行進(jìn)一步處理。

另一種可能性是通過使用path()實(shí)例列表包括其他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中刪除重復(fù)使用單個(gè)模式前綴的冗余。例如,考慮以下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),
]

我們可以通過只聲明一次公共路徑前綴并對(duì)不同的后綴進(jìn)行分組來改善這一點(diǎn):

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

捕捉的參數(shù)

包含的URLconf從父URLconfs接收任何捕獲的參數(shù),因此以下示例有效:

# 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"變量按預(yù)期傳遞給包含的URLconf。

傳遞額外的選項(xiàng)來查看函數(shù)

URLconfs有一個(gè)鉤子,可讓您將額外的參數(shù)作為Python字典傳遞給視圖函數(shù)。

path()函數(shù)可以使用可選的第三個(gè)參數(shù),該參數(shù)應(yīng)該是傳遞給view函數(shù)的額外關(guān)鍵字參數(shù)的字典。

例如:

from django.urls import path
from . import views

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

在此示例中,對(duì)于的請(qǐng)求/blog/2005/,Django將調(diào)用 。views.year_archive(request, year=2005, foo='bar')

該技術(shù)在 聯(lián)合框架中用于將元數(shù)據(jù)和選項(xiàng)傳遞給視圖。

處理沖突

URL模式可能會(huì)捕獲命名的關(guān)鍵字參數(shù),并在其額外參數(shù)字典中傳遞具有相同名稱的參數(shù)。發(fā)生這種情況時(shí),將使用字典中的參數(shù)代替URL中捕獲的參數(shù)。

將額外的選項(xiàng)傳遞給include()

同樣,您可以將額外選項(xiàng)傳遞給include(),所包含的URLconf中的每一行都將傳遞額外選項(xiàng)。

例如,這兩個(gè)URLconf集在功能上是相同的:

設(shè)置一:

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

設(shè)置二:

# 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}),
]

請(qǐng)注意,無論行的視圖是否實(shí)際接受這些選項(xiàng),額外的選項(xiàng)將始終傳遞到所包含的URLconf中的每一行。因此,僅當(dāng)您確定所包含的URLconf中的每個(gè)視圖都接受要傳遞的額外選項(xiàng)時(shí),此技術(shù)才有用。

URL的反向解析

在Django項(xiàng)目上進(jìn)行工作時(shí),通常需要獲取最終形式的URL,以嵌入生成的內(nèi)容(視圖和資產(chǎn)URL,向用戶顯示的URL等)或在服務(wù)器上處理導(dǎo)航流程側(cè)面(重定向等)

強(qiáng)烈希望避免對(duì)這些URL進(jìn)行硬編碼(一種費(fèi)力,不可擴(kuò)展且易于出錯(cuò)的策略)。同樣危險(xiǎn)的是,設(shè)計(jì)臨時(shí)機(jī)制來生成與URLconf描述的設(shè)計(jì)平行的URL,這可能導(dǎo)致URL的生成隨著時(shí)間的推移而變得陳舊。

換句話說,需要一種DRY機(jī)制。除其他優(yōu)點(diǎn)外,它還允許URL設(shè)計(jì)的發(fā)展,而不必遍歷所有項(xiàng)目源代碼來搜索和替換過時(shí)的URL。

我們可以獲得URL的主要信息是負(fù)責(zé)處理它的視圖的標(biāo)識(shí)(例如名稱)。視圖參數(shù)的類型(位置,關(guān)鍵字)和值還必須包含在正確的URL查找中的其他信息。

Django提供了一個(gè)解決方案,使得URL映射器是URL設(shè)計(jì)的唯一存儲(chǔ)庫(kù)。您將其與URLconf一起提供,然后可以在兩個(gè)方向上使用它:

  • 從用戶/瀏覽器請(qǐng)求的URL開始,它將調(diào)用正確的Django視圖,以提供可能需要的任何參數(shù)以及從URL中提取的值。
  • 從標(biāo)識(shí)相應(yīng)的Django視圖以及將傳遞給該視圖的參數(shù)值開始,獲取關(guān)聯(lián)的URL。

第一個(gè)是我們?cè)谏弦还?jié)中討論的用法。第二種是所謂的URL反向解析,反向URL匹配,反向URL查找或簡(jiǎn)稱URL反向。

Django提供了執(zhí)行URL反轉(zhuǎn)的工具,這些工具與需要URL的不同層相匹配:

  • 在模板中:使用url模板標(biāo)記。
  • 在Python代碼中:使用reverse()函數(shù)。
  • 與Django模型實(shí)例的URL處理相關(guān)的高級(jí)代碼:get_absolute_url()方法。

例子

再次考慮以下URLconf條目:

from django.urls import path

from . import views

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

根據(jù)這種設(shè)計(jì),對(duì)應(yīng)于年度歸檔文件的URL NNNN 是/articles//。

您可以使用以下模板代碼獲取它們:

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

如果出于某種原因決定更改發(fā)布年度文章存檔內(nèi)容的URL,則只需要更改URLconf中的條目即可。

在視圖具有一般性質(zhì)的某些情況下,URL和視圖之間可能存在多對(duì)一關(guān)系。對(duì)于這些情況,在反向URL時(shí),視圖名稱并不是一個(gè)足夠好的標(biāo)識(shí)符。閱讀下一節(jié)以了解Django為此提供的解決方案。

命名URL模式

為了執(zhí)行URL反向,您需要 像上面的示例一樣使用命名的URL模式。URL名稱使用的字符串可以包含您喜歡的任何字符。您不限于有效的Python名稱。

在命名URL模式時(shí),請(qǐng)選擇不太可能與其他應(yīng)用程序的名稱沖突的名稱。如果調(diào)用URL模式,comment 而另一個(gè)應(yīng)用程序執(zhí)行相同的操作,則reverse()找到的URL 取決于項(xiàng)目urlpatterns列表中最后一個(gè)模式。

在您的URL名稱上添加前綴(可能源自應(yīng)用程序名稱(例如myapp-comment而不是comment)),可以減少發(fā)生沖突的機(jī)會(huì)。

如果要覆蓋視圖,可以故意選擇與另一個(gè)應(yīng)用程序相同的URL名稱。例如,一個(gè)常見的用例是覆蓋 LoginView。Django和大多數(shù)第三方應(yīng)用程序的某些部分假定此視圖具有名稱為的URL模式 login。如果你有一個(gè)自定義登錄查看,并給它的URL的名字login, reverse()會(huì)發(fā)現(xiàn)自定義視圖,只要它在 urlpatterns以后django.contrib.auth.urls包括(如果這是包含在所有)。

如果多個(gè)URL模式的參數(shù)不同,也可以使用相同的名稱。除URL名稱外,還要reverse() 匹配參數(shù)數(shù)量和關(guān)鍵字參數(shù)的名稱。

URL命名空間

簡(jiǎn)介

URL名稱空間允許您唯一地反向命名URL模式,即使不同的應(yīng)用程序使用相同的URL名稱。對(duì)于第三方應(yīng)用程序,始終使用命名空間的URL是一個(gè)好習(xí)慣(就像我們?cè)诒窘坛讨兴龅哪菢樱M瑯?,如果部署了一個(gè)應(yīng)用程序的多個(gè)實(shí)例,它還允許您反向URL。換句話說,由于單個(gè)應(yīng)用程序的多個(gè)實(shí)例將共享命名URL,因此名稱空間提供了一種區(qū)分這些命名URL的方法。

對(duì)于特定站點(diǎn),可以多次使用正確使用URL名稱空間的Django應(yīng)用程序。例如,django.contrib.admin 有一AdminSite類允許您 部署多個(gè)admin實(shí)例。在下一個(gè)示例中,我們將討論從教程在兩個(gè)不同位置部署民意調(diào)查應(yīng)用程序的想法,以便我們可以為兩個(gè)不同的受眾(作者和發(fā)布者)提供相同的功能。

URL名稱空間分為兩部分,都是字符串:

  • 應(yīng)用程序名稱空間這描述了正在部署的應(yīng)用程序的名稱。單個(gè)應(yīng)用程序的每個(gè)實(shí)例將具有相同的應(yīng)用程序名稱空間。例如,Django的admin應(yīng)用程序具有可預(yù)測(cè)的應(yīng)用程序名稱空間'admin'。
  • 實(shí)例名稱空間這標(biāo)識(shí)了應(yīng)用程序的特定實(shí)例。實(shí)例名稱空間在整個(gè)項(xiàng)目中應(yīng)該是唯一的。但是,實(shí)例名稱空間可以與應(yīng)用程序名稱空間相同。這用于指定應(yīng)用程序的默認(rèn)實(shí)例。例如,默認(rèn)Django管理實(shí)例的實(shí)例名稱空間為'admin'。

使用':'操作符指定以名稱分隔的URL 。例如,使用引用管理應(yīng)用程序的主索引頁(yè)面'admin:index'。這表示的命名空間'admin',以及的命名URL 'index'。

命名空間也可以嵌套。命名的URL 'sports:polls:index'將尋找'index'在命名空間中命名的模式,該模式'polls'本身是在頂級(jí)命名空間中定義的'sports'。

反向命名空間的URL

給定'polls:index'要解析的命名空間URL(例如)后,Django會(huì)將完全限定的名稱拆分為多個(gè)部分,然后嘗試以下查找:

  1. 首先,Django尋找匹配的應(yīng)用程序名稱空間(在本示例中為'polls')。這將產(chǎn)生該應(yīng)用程序?qū)嵗牧斜怼?/li>
  2. 如果定義了當(dāng)前應(yīng)用程序,則Django查找并返回該實(shí)例的URL解析器。可以使用 函數(shù)的current_app參數(shù)指定當(dāng)前應(yīng)用程序reverse()。該url模板標(biāo)簽使用當(dāng)前解決視圖在當(dāng)前應(yīng)用程序的命名空間 RequestContext。您可以通過在request.current_app屬性上設(shè)置當(dāng)前應(yīng)用程序來覆蓋此默認(rèn)設(shè)置。
  3. 如果沒有當(dāng)前應(yīng)用程序,則Django將查找默認(rèn)應(yīng)用程序?qū)嵗?。默認(rèn)的應(yīng)用程序?qū)嵗蔷哂性搶?shí)例實(shí)例命名空間匹配應(yīng)用的命名空間(在此示例中,的一個(gè)實(shí)例polls稱為'polls')。
  4. 如果沒有默認(rèn)應(yīng)用程序?qū)嵗?,則Django將選擇該應(yīng)用程序的最后部署實(shí)例,無論其實(shí)例名稱是什么。
  5. 如果在步驟1中提供的名稱空間與應(yīng)用程序名稱空間不匹配,Django將嘗試直接查找該名稱空間作為 實(shí)例名稱空間。

如果存在嵌套的名稱空間,則對(duì)名稱空間的每個(gè)部分重復(fù)這些步驟,直到僅解析視圖名稱為止。然后,將視圖名稱解析為找到的名稱空間中的URL。

例子

為了展示該解決方案的實(shí)際作用,請(qǐng)考慮polls本教程中應(yīng)用程序的兩個(gè)實(shí)例的示例:一個(gè)稱為'author-polls' ,一個(gè)稱為'publisher-polls'。假設(shè)我們已經(jīng)增強(qiáng)了該應(yīng)用程序,以便在創(chuàng)建和顯示民意測(cè)驗(yàn)時(shí)考慮實(shí)例名稱空間。

的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')),
]

民調(diào)/的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'),
    ...
]

使用此設(shè)置,可以進(jìn)行以下查找:

  • 如果其中一個(gè)實(shí)例就是當(dāng)前-就是說,如果我們?cè)诶L制實(shí)例詳細(xì)信息頁(yè)面'author-polls'- 'polls:index'解析到的索引頁(yè)面'author-polls'實(shí)例; 即以下兩個(gè)都將導(dǎo)致"/author-polls/"。在基于類的視圖的方法中:reverse('polls:index', current_app=self.request.resolver_match.namespace)并在模板中:{% url 'polls:index' %}
  • 如果沒有當(dāng)前實(shí)例(例如,如果我們正在網(wǎng)站上其他地方渲染頁(yè)面),'polls:index'則將解析為的最后一個(gè)注冊(cè)實(shí)例polls。由于沒有默認(rèn)實(shí)例(的實(shí)例名稱空間'polls'),因此polls將使用該實(shí)例的最后一個(gè)實(shí)例。這是'publisher-polls'因?yàn)樗谥斜宦暶鳛樽詈笠粋€(gè)urlpatterns。
  • 'author-polls:index'將始終解析為實(shí)例的索引頁(yè) 'author-polls'('publisher-polls')。

如果還存在一個(gè)默認(rèn)實(shí)例(即名為的實(shí)例)'polls',則唯一的更改就是沒有當(dāng)前實(shí)例(上面列表中的第二項(xiàng))。在這種情況下,'polls:index' 它將解析為默認(rèn)實(shí)例的索引頁(yè),而不是最后一個(gè)在中聲明的實(shí)例urlpatterns。

URL命名空間和包含的URLconf 

可以通過兩種方式指定包含的URLconf的應(yīng)用程序名稱空間。

首先,您可以app_name在包含的URLconf模塊中設(shè)置與該urlpatterns屬性相同級(jí)別的屬性。您必須將實(shí)際模塊或?qū)υ撃K的字符串引用傳遞給include(),而不是其urlpatterns自身的列表。

民調(diào)/的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')),
]

中定義的URL polls.urls將具有一個(gè)應(yīng)用程序名稱空間polls。

其次,您可以包括一個(gè)包含嵌入式名稱空間數(shù)據(jù)的對(duì)象。如果您include()列出path()re_path()實(shí)例,則該對(duì)象中包含的URL將被添加到全局名稱空間中。但是,您還可以include()包含一個(gè)包含以下內(nèi)容的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)),
]

這會(huì)將提名的URL模式包括到給定的應(yīng)用程序名稱空間中。

可以使用的namespace參數(shù) 指定實(shí)例名稱空間include()。如果未指定實(shí)例名稱空間,它將默認(rèn)為包含的URLconf的應(yīng)用程序名稱空間。這意味著它將也是該名稱空間的默認(rèn)實(shí)例。

詳細(xì)參考: https://docs.djangoproject.com/en/3.0/topics/http/urls/


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)