欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Django url 路由匹配過程詳解

 更新時間:2021年01月22日 14:18:15   作者:Guixian  
這篇文章主要介紹了Django url 路由匹配過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1 Django 如何處理一個請求

當一個用戶請求Django 站點的一個頁面,下面是Django 系統(tǒng)決定執(zhí)行哪個Python 代碼使用的算法:

Django 確定使用根 URLconf 模塊。通常,這是 ROOT_URLCONF 設(shè)置的值(即 settings 中的 ROOT_URLCONF),但如果傳入 HttpRequest 對象擁有 urlconf 屬性(通過中間件設(shè)置),它的值將被用來代替 ROOT_URLCONF 設(shè)置??梢栽?django/core/handlers/base.py 發(fā)現(xiàn)該邏輯。

class BaseHandler:
  ...
  def _get_response(self, request):
    ...
    if hasattr(request, 'urlconf'):
      urlconf = request.urlconf
      set_urlconf(urlconf)
      resolver = get_resolver(urlconf)
    else:
      resolver = get_resolver()

Django 加載該 Python 模塊并尋找可用的 urlpatterns 。它是 django.urls.path() 和(或) django.urls.re_path() 實例的序列(sequence)。其實就是我們寫的 url.py

Django 會按順序遍歷每個 URL 模式,然后會在所請求的URL匹配到第一個模式后停止,并與 path_info 匹配。這個是路由匹配的關(guān)鍵,相關(guān)邏輯均在django/urls/resolvers.py。其中有幾個比較重要的概念,如RegexPattern、RoutePattern、URLPattern、URLResolver。其中URLResolver有嵌套的邏輯,下文詳述。

一旦有 URL 匹配成功,Django 導入并調(diào)用相關(guān)的視圖,這個視圖是一個Python 函數(shù)(或基于類的視圖 class-based view )。匹配成功會返回一個ResolverMatch對象。

如果沒有 URL 被匹配,或者匹配過程中出現(xiàn)了異常,Django 會調(diào)用一個適當?shù)腻e誤處理視圖。

本文詳述 2、3,即 urlpatterns 相關(guān)概念和路由匹配的過程。

2 URL 配置文件

在 Django 2 之后通常會使用 path/re_path 來設(shè)置路由,還要一個比較特殊的方法 include 。

  • path: 用于普通路徑
  • re_path:用于正則路徑
  • include: 將一個子 url 配置文件導入

如下示例:

urlpatterns = [
  path('index/', views.index), # 普通路徑
  re_path(r'^articles/([0-9]{4})/$', views.articles), # 正則路徑
  path("app01/", include("app01.urls")),
]

上面的配置文件,設(shè)置了3條 urlpattern,分別是普通路徑 index/ 與 視圖函數(shù) views.index,正則路徑 ^articles/([0-9]{4})/$ 與視圖函數(shù) views.articles 綁定。app01/ 和app01.urls 綁定,app01.urls 不是一個視圖函數(shù),而是一個子模塊的 urlpatterns。
可以看到 urlpattern 可以把一個 url 和視圖函數(shù)綁定,也可以和一個子 urlpattern 進行綁定。

2.1 path、re_path

設(shè)置路由的幾個函數(shù)均定義在 django/urls/conf.py 中。

def include(arg, namespace=None):
  ...
  return (urlconf_module, app_name, namespace)


def _path(route, view, kwargs=None, name=None, Pattern=None):
  if isinstance(view, (list, tuple)):
    # For include(...) processing.
    pattern = Pattern(route, is_endpoint=False)
    urlconf_module, app_name, namespace = view
    return URLResolver(
      pattern,
      urlconf_module,
      kwargs,
      app_name=app_name,
      namespace=namespace,
    )
  elif callable(view):
    pattern = Pattern(route, name=name, is_endpoint=True)
    return URLPattern(pattern, view, kwargs, name)
  else:
    raise TypeError('view must be a callable or a list/tuple in the case of include().')


path = partial(_path, Pattern=RoutePattern)
re_path = partial(_path, Pattern=RegexPattern)

首先先來看下 path 和 re_path,這兩個函數(shù)分別被 functools 下面的 partial 封裝了一下。partial 的作用簡單來說就是將一個函數(shù)的某些參數(shù)給固定住,返回一個新的函數(shù)。詳細文檔可以查看partial 文檔。
這樣就不難理解 path 和 re_path,他們就是就是綁定了不同的 Pattern 參數(shù)的 _path 函數(shù)。進一步查看 _path 內(nèi)部的邏輯,

第一個分支 如果綁定的是一個 list或者tuple,使用 URLResolver 去解析,其實此時就是使用了 include 來定義 urlpattern。
另外一種情況如果綁定的 view 是可以調(diào)用的,那就使用 URLPattern 去解析。URLPattern 中的 pattern 參數(shù)就是根據(jù)是采用 path/re_path 方法分別對應 RoutePattern/RegexPattern。

2.2 include

def include(arg, namespace=None):
  ...
  if isinstance(urlconf_module, str):
    urlconf_module = import_module(urlconf_module)
  patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)
  app_name = getattr(urlconf_module, 'app_name', app_name)
  ...
  return (urlconf_module, app_name, namespace)

include 方法所做的工作就是通過 import_module 將定義的 url 模塊導入。返回一個由子 urlconf 模塊、app_name、命名空間 namespace 組成的元組?;氐絼倓偵厦娴?_path 中第一個分支。將這個元組里面參數(shù)代入 URLResolver 并返回。

3 URLPattern 與 URLResolver

3.1 URLPattern

上面提到如果url定義中綁定是一個可以直接調(diào)用的view。那就是使用URLPattern直接去解析。

class URLPattern:
  def __init__(self, pattern, callback, default_args=None, name=None):
    # 需要匹配的 urlpattern,這里根據(jù)是path還是re_path 分別是 RoutePattern或RegexPattern的實例
    self.pattern = pattern
    self.callback = callback # the view
    self.default_args = default_args or {}
    self.name = name
  ...
  def resolve(self, path):
    調(diào)用 RoutePattern 或 RegexPattern 的實例中的 match 方法進行匹配(注意這里不是 re 模塊里面的 match)
    match = self.pattern.match(path)
    if match:
      new_path, args, kwargs = match
      # Pass any extra_kwargs as **kwargs.
      kwargs.update(self.default_args)
      # 匹配成功返回 `ResolverMatch`
      return ResolverMatch(self.callback, args, kwargs, self.pattern.name, route=str(self.pattern))
  ...

URLPattern 初始化時其中的 pattern 就是根據(jù)是使用 path/re_path 分別對應RoutePattern或RegexPattern。其實就是指定匹配的模式是普通路由還是正則的路由。

3.2 URLResolver

URLResolver 源碼中比較核心的是 resolve 函數(shù),就是傳入一個 path,進行匹配。

class URLResolver:
  def resolve(self, path):
    path = str(path) # path may be a reverse_lazy object
    tried = []
    # 匹配 path
    match = self.pattern.match(path)
    if match:
      new_path, args, kwargs = match
      # 如果匹配成功,則繼續(xù)匹配它的url_patterns
      for pattern in self.url_patterns:
        try:
          # 這個pattern可能是URLPattern,也可能是URLResolver;如果是URLPattern,匹配成功則返回ResolverMatch;如果是URLResolver,則會遞歸調(diào)用下去。
          sub_match = pattern.resolve(new_path)
        ...
        else:
          if sub_match:
            ...
            # 匹配成功返回ResolverMatch
            return ResolverMatch(
              sub_match.func,
              sub_match_args,
              sub_match_dict,
              sub_match.url_name,
              [self.app_name] + sub_match.app_names,
              [self.namespace] + sub_match.namespaces,
              self._join_route(current_route, sub_match.route),
            )
          tried.append([pattern])
      raise Resolver404({'tried': tried, 'path': new_path})
    raise Resolver404({'path': path})

URLResolver 比較關(guān)鍵的邏輯在 循環(huán)匹配 pattern 過程,如果 pattern是URLPattern匹配成功直接返回ResolverMatch,如果是另一個URLResolver,則實現(xiàn)了遞歸調(diào)用。

Django 就是通過這個 URLResolver 實現(xiàn)了多級 URL 配置。

4 總結(jié)

Django 路由匹配的有幾個比較核心的概念 path/re_path/include、RegexPattern/RoutePattern、URLPattern/URLResolver。
首先用 partial 封裝 _path,綁定了一個 pattern 匹配模式(RegexPattern/RoutePattern),后面多次用到了這個 pattern。然后就是根據(jù) view 是元組還是可調(diào)用視圖函數(shù),分別使用URLResolver和URLPattern去解析,這兩個類解析之后都會返回給ResolverMatch,由它去回調(diào)匹配成功后的結(jié)果(view和args等)。

本文從全局的角度大致說明了Django路由的匹配流程,后續(xù)將從細節(jié)部分說明其中的一些關(guān)鍵點。

到此這篇關(guān)于Django url 路由匹配過程詳解的文章就介紹到這了,更多相關(guān)Django url 路由匹配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python中defaultdict用法實例詳解

    python中defaultdict用法實例詳解

    python中的dict是一個重要的數(shù)據(jù)類型,知道如何使用這個數(shù)據(jù)類型很簡單,但是這個類型使用過程中容易進入一些誤區(qū),下面這篇文章主要給大家介紹了關(guān)于python中defaultdict用法的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • python實現(xiàn)SMTP郵件發(fā)送功能

    python實現(xiàn)SMTP郵件發(fā)送功能

    這篇文章主要為大家詳細介紹了python實現(xiàn)SMTP郵件發(fā)送功能的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • python3 scrapy框架的執(zhí)行流程

    python3 scrapy框架的執(zhí)行流程

    Scrapy的安裝有多種方式,它支持Python2.7版本及以上或Python3.3版本及以上。下面說明python3 scrapy框架的常用命令及框架執(zhí)行流程,感興趣的朋友一起看看吧
    2021-07-07
  • 使用Python批量處理Excel文件并轉(zhuǎn)為csv文件示例

    使用Python批量處理Excel文件并轉(zhuǎn)為csv文件示例

    這篇文章主要介紹了使用Python批量處理Excel文件并轉(zhuǎn)為csv文件示例,文中通過代碼示例給大家介紹非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2023-12-12
  • Python腳本實現(xiàn)蝦米網(wǎng)簽到功能

    Python腳本實現(xiàn)蝦米網(wǎng)簽到功能

    這篇文章主要介紹了Python腳本實現(xiàn)蝦米網(wǎng)簽到功能的方法,涉及Python調(diào)用URL模塊實現(xiàn)數(shù)據(jù)傳輸與處理的相關(guān)技巧,需要的朋友可以參考下
    2016-04-04
  • python利用pandas和csv包向一個csv文件寫入或追加數(shù)據(jù)

    python利用pandas和csv包向一個csv文件寫入或追加數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于python利用pandas和csv包向一個csv文件寫入或追加數(shù)據(jù)的相關(guān)資料,我們越來越多的使用pandas進行數(shù)據(jù)處理,有時需要向一個已經(jīng)存在的csv文件寫入數(shù)據(jù),需要的朋友可以參考下
    2023-07-07
  • Pyhacker實現(xiàn)端口掃描器

    Pyhacker實現(xiàn)端口掃描器

    這篇文章主要為大家介紹了Pyhacker實現(xiàn)端口掃描器的過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 基于python3抓取pinpoint應用信息入庫

    基于python3抓取pinpoint應用信息入庫

    這篇文章主要介紹了基于python3抓取pinpoint應用信息入庫,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Anaconda虛擬環(huán)境配置Python庫與Spyder編譯器的方法

    Anaconda虛擬環(huán)境配置Python庫與Spyder編譯器的方法

    在文章創(chuàng)建Anaconda虛擬Python環(huán)境的方法中,我們介紹了在Anaconda環(huán)境下,創(chuàng)建、使用與刪除Python虛擬環(huán)境的方法,而創(chuàng)建虛擬環(huán)境后,就需要在對應的環(huán)境內(nèi)配置各類庫與軟件,本文就對這些操作加以介紹,感興趣的朋友感興趣的朋友一起看看吧
    2024-04-04
  • 用Python快速讀取Excel數(shù)據(jù)

    用Python快速讀取Excel數(shù)據(jù)

    嘿,想學會用Python快速讀取Excel數(shù)據(jù)嗎?不用擔心,這個指南將帶你輕松掌握這項技能,讓我們一起開始吧!
    2023-12-12

最新評論