URL 分发器

干净、优雅的 URL 方案是高质量 Web 应用程序的重要细节。Django 允许您根据自己的意愿设计 URL,不受框架限制。

请参阅 Cool URIs don’t change,由万维网创建者 Tim Berners-Lee 撰写,其中给出了关于为什么 URL 应该干净且易用的出色论据。

概述

要为应用程序设计 URL,您需要创建一个 Python 模块,非正式地称为 URLconf(URL 配置)。此模块是纯 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) 方法,用于处理将匹配的字符串转换为应传递给视图函数的类型。如果无法转换给定值,它应该引发 ValueError。一个 ValueError 被解释为没有匹配,因此会向用户发送 404 响应,除非其他 URL 模式匹配。
  • 一个 to_url(self, value) 方法,用于处理将 Python 类型转换为要在 URL 中使用的字符串。如果无法转换给定值,它应该引发 ValueError。一个 ValueError 被解释为没有匹配,因此 reverse() 将引发 NoReverseMatch,除非其他 URL 模式匹配。

例如

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

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

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

在您的 URLconf 中使用 register_converter() 注册自定义转换器类

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

使用正则表达式

如果路径和转换器语法不足以定义您的 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_articles,并带有两个位置参数:page-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 应该是一个 sequence,包含 path() 和/或 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 中,单个模式前缀被重复使用。例如,考虑这个 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 字典传递给你的视图函数。

The 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')

这种技术在 syndication framework 中被用来向视图传递元数据和选项。

处理冲突

有可能存在一个 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 的信息是视图参数的类型(位置、关键字)和值。

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,那么 reverse() 将找到你的自定义视图,只要它在 urlpatterns 中位于 django.contrib.auth.urls 包含之后(如果它被包含的话)。

如果你想覆盖一个视图,你可以故意选择与另一个应用程序相同的 URL 名称。例如,一个常见的用例是覆盖 LoginView。Django 的部分内容和大多数第三方应用程序都假设此视图有一个名为 login 的 URL 模式。如果你有一个自定义登录视图,并将其 URL 命名为 login,那么 reverse() 将找到你的自定义视图,只要它在 urlpatterns 中位于 django.contrib.auth.urls 包含之后(如果它被包含的话)。

URL 命名空间

简介

URL 命名空间允许你唯一地反转 命名的 URL 模式,即使不同的应用程序使用相同的 URL 名称。对于第三方应用程序来说,始终使用命名空间 URL 是一种良好的实践(就像我们在教程中所做的那样)。同样,它也允许你在部署应用程序的多个实例时反转 URL。换句话说,由于单个应用程序的多个实例将共享命名的 URL,因此命名空间提供了一种区分这些命名 URL 的方法。

正确使用 URL 命名空间的 Django 应用程序可以为特定站点部署多次。例如,django.contrib.admin 有一个 AdminSite 类,它允许你 部署多个管理实例。在后面的示例中,我们将讨论将教程中的 polls 应用程序部署到两个不同位置的想法,以便我们可以向两个不同的受众(作者和发布者)提供相同的功能。

URL 命名空间由两部分组成,这两部分都是字符串。

应用程序命名空间
这描述了正在部署的应用程序的名称。单个应用程序的每个实例都将具有相同的应用程序命名空间。例如,Django 的管理应用程序具有一个相当可预测的应用程序命名空间 'admin'
实例命名空间
这标识了应用程序的特定实例。实例命名空间应在整个项目中保持唯一。但是,实例命名空间可以与应用程序命名空间相同。这用于指定应用程序的默认实例。例如,默认的 Django 管理实例的实例命名空间为 'admin'

命名空间 URL 使用 ':' 运算符指定。例如,管理应用程序的主索引页面使用 'admin:index' 引用。这表示命名空间为 'admin',命名 URL 为 'index'

命名空间也可以嵌套。命名 URL 'sports:polls:index' 将在命名空间 'polls' 中查找名为 'index' 的模式,该命名空间本身在顶级命名空间 'sports' 中定义。

反转命名空间 URL

当给定一个命名空间 URL(例如 'polls:index')来解析时,Django 会将完全限定的名称拆分为多个部分,然后尝试以下查找。

  1. 首先,Django 会查找匹配的 应用程序命名空间(在本例中为 'polls')。这将产生该应用程序实例的列表。

  2. 如果当前定义了应用程序,Django 会找到并返回该实例的 URL 解析器。当前应用程序可以通过 current_app 参数指定给 reverse() 函数。

    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 命名空间和包含的 URLconf

包含的 URLconf 的应用程序命名空间可以通过两种方式指定。

首先,您可以在包含的 URLconf 模块中设置一个 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 模式包含到给定的应用程序命名空间中。

可以使用 namespace 参数传递给 include() 来指定实例命名空间。如果未指定实例命名空间,则默认使用包含的 URLconf 的应用程序命名空间。这意味着它也将成为该命名空间的默认实例。

返回顶部