--- title: 路由(Urls) date: 2020-10-30 17:13:36 tags: [Django, Urls] categories: [Django] author: Anges黎梦 --- ## 什么是URL? >​ URL(Uniform Resource Locator,统一资源定位符)是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,用于指出文件的路径位置。也就可以理解为,URL就是常说的网址,每一个地址代表了不同的网页,在Django中,URL也成为URLconf。 ## 初始项目的urls ![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/django/demo.png) 这是一个纯净项目的url配置文件,他存在的目录,是与setting文件在同一个目录中。 urlpatterns,就是一个保存url配置的变量,他的类型是list。 创建项目之后,这个文件中有一些例子了。 但是他在注释中也给了我们一些其他的用法。 第一种,就是他例子中的直接相对地址加上视图函数的名称。 第二种,则是导入urls文件,这样也给了我们其他更方便的配置方法,不必把所有的内容写到一个文件下。 我们可以通过include的方式把在其他位置写好的url配置文件导入进去。 同时,路径的匹配,还支持正则表达式。 ``` # 导入Admin功能模块 from django.contrib import admin # 导入URL编写模块 from django.urls import path # urlpatterns 整个项目的url集合,每一个元素代表一条url信息 urlpatterns = [ # 设定admin的url path('admin/', admin.site.urls), ] ``` 'admin/' 代表的是127.0.0.1:8000/admin的地址,后面的斜杠是路径分隔符。 admin.site.urls是url的处理函数,即视图函数 ## URLconfs中的方法 ### path() path**(***route***,** *view***,** *kwargs=None***,** *name=None***)** 返回包含在中的元素`urlpatterns` ``` from django.urls import include, path urlpatterns = [ path('index/', views.index, name='main-view'), path('bio//', views.bio, name='bio'), path('articles//', views.article, name='article-detail'), path('articles///', views.section, name='article-section'), path('weblog/', include('blog.urls')), ... ] ``` **route**参数应该是一个字符串或 gettext_lazy(),其中包含一个URL模式。该字符串可能包含尖括号(``如上所示)以捕获URL的一部分并将其作为关键字参数发送到视图。尖括号可以包括转换器规范(如`int`部分``),其限制匹配的字符并且还可以改变传递给视图的变量的类型。例如,``匹配一串十进制数字并将值转换为a `int`。 `view`参数是一个视图函数或的结果 as_view()为基于类的视图。它也可以是一个django.urls.include()。 该`kwargs`参数允许您将其他参数传递给视图函数或方法。 有关 name参数的内容,见url命名空间。 ### re_path() `re_path`**(***route***,** *view***,** *kwargs=None***,** *name=None***)** ``` from django.urls import include, re_path urlpatterns = [ re_path(r'^index/$', views.index, name='index'), re_path(r'^bio/(?P\w+)/$', views.bio, name='bio'), re_path(r'^weblog/', include('blog.urls')), ... ] ``` 该`route`参数应该是一个字符串或 gettext_lazy(),其中包含与Python的兼容的正则表达式 re模块。字符串通常使用原始字符串语法(`r''`),以便它们可以包含序列,`\d`而无需使用另一个反斜杠转义反斜杠。进行匹配时,将正则表达式中捕获的组传递给视图 - 如果组已命名,则作为命名参数,否则作为位置参数。值以字符串形式传递,不进行任何类型转换。 的`view`,`kwargs`和`name`参数是一样的 path() ### include() `include`(*module*,*namespace = None*) `include`(*pattern_list*) `include`(*(pattern_list*,*app_namespace)*,*namespace = None*) 一个函数,它将完整的Python导入路径带到另一个URLconf模块,该模块应该“包含”在这个地方。可选地,还可以指定将包括条目的应用程序命名空间和实例命名空间。 通常,应用程序命名空间应由包含的模块指定。如果设置了应用程序命名空间,则该`namespace`参数可用于设置不同的实例命名空间。 `include()` 也接受返回URL模式的iterable或包含此类iterable的2元组以及应用程序命名空间的名称作为参数。 More Actions参数: - **module** - URLconf模块(或模块名称) - **namespace**([*str*](https://docs.python.org/3/library/stdtypes.html#str)) - 包含的URL条目的实例名称空间 - **pattern_list** - Iterable [`path()`](https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.path)和/或[`re_path()`](https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.re_path)实例。 - **app_namespace**([*str*](https://docs.python.org/3/library/stdtypes.html#str)) - 包含的URL条目的应用程序命名空间 ### `register_converter()` `register_converter`(*converter*,*type_name*) 注册转换器以在s中使用的功能。path route 该`converter`参数是一个转换器类,并且`type_name`是在路径模式来使用转换器的名称。 ## URLconfs中使用的函数 ### static() - `static.``static`(*前缀*,*视图= django.views.static.serve*,*** kwargs*) Helper函数在调试模式下返回服务文件的URL模式: ``` from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # ... the rest of your URLconf goes here ... ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ``` ## URL调度程序 干净,优雅的URL方案是高质量Web应用程序中的重要细节。Django允许您根据需要设计URL,没有框架限制。 没有`.php`或没有`.cgi`必要,当然也没有 `0,2097,1-1-1928,00`废话。 ### 概述 要设计应用程序的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`。这应该是Python列表`django.urls.path()` 和/或`django.urls.re_path()`实例。 3. Django按顺序遍历每个URL模式,并在匹配请求的URL的第一个模式停止。 4. 一旦其中一个URL模式匹配,Django就会导入并调用给定的视图,这是一个简单的Python函数(或基于 类的视图 )。视图传递以下参数: - 一个例子`HttpRequest`。 - 如果匹配的URL模式未返回任何命名组,则正则表达式中的匹配将作为位置参数提供。 - 关键字参数由路径表达式匹配的任何命名部分组成,由或者 可选`kwargs`参数中指定的任何参数覆盖 。`django.urls.path()``django.urls.re_path()` 5. 如果没有URL模式匹配,或者在此过程中的任何点期间引发异常,Django将调用适当的错误处理视图。请参阅下面的错误处理。 ### 示例 这是一个示例URLconf: ``` from django.urls import path from . import views urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles//', views.year_archive), path('articles///', views.month_archive), path('articles////', views.article_detail), ] ``` 笔记: - 要从URL捕获值,请使用尖括号。 - 捕获的值可以选择包括转换器类型。例如,用于 ``捕获整数参数。如果未包含转换器`/`,则匹配除字符之外的任何字符串。 - 没有必要添加前导斜杠,因为每个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`](https://docs.python.org/3/library/uuid.html#uuid.UUID)实例。 - `path`- 匹配任何非空字符串,包括路径分隔符 `'/'`。这允许您匹配完整的URL路径,而不仅仅是URL路径的一部分`str`。 ## 注册自定义路径转换器 对于更复杂的匹配要求,您可以定义自己的路径转换器。 转换器是一个包含以下内容的类: - 一个`regex`class属性,作为字符串。 - 甲方法,它处理匹配的字符串转换成要传递到视图函数的类型。如果它不能转换给定值,它应该提高。`to_python(self,value)``ValueError` - 一种方法,用于处理将Python类型转换为要在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中注册自定义转换器类 : ``` 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//', views.year_archive), ... ] ``` ## 使用正则表达式 如果路径和转换器语法不足以定义URL模式,则还可以使用正则表达式。为此,请使用 `re_path()`而不是`path()`。 在Python正则表达式中,命名正则表达式组的语法是`(?Ppattern)`,组`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[0-9]{4})/$', views.year_archive), re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive), re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[\w-]+)/$', views.article_detail), ] ``` 这完成了与前一个示例大致相同的事情,除了: - 匹配的确切网址稍微受限制。例如,年份10000将不再匹配,因为年份整数被限制为恰好四位数。 - 无论正则表达式的匹配类型如何,每个捕获的参数都将作为字符串发送到视图。 从使用切换`path()`到 `re_path()`反之亦然,特别重要的是要注意视图参数的类型可能会发生变化,因此您可能需要调整视图。 ## 使用未命名的正则表达式组 除了命名组语法之外,例如`(?P[0-9]{4})`,您还可以使用较短的未命名组,例如`([0-9]{4})`。 不特别推荐这种用法,因为它更容易在匹配的预期含义和视图的参数之间意外引入错误。 在任何一种情况下,建议在给定的正则表达式中仅使用一种样式。当两种样式混合使用时,将忽略任何未命名的组,并且只将命名组传递给视图函数。 ## 嵌套参数 正则表达式允许嵌套参数,Django将解析它们并将它们传递给视图。反转时,Django将尝试填充所有外部捕获的参数,忽略任何嵌套捕获的参数。考虑以下URL模式,它们可选地采用页面参数: ``` from django.urls import re_path urlpatterns = [ re_path(r'^blog/(page-(\d+)/)?$', blog_articles), # bad re_path(r'^comments/(?:page-(?P\d+)/)?$', comments), # good ] ``` 两种模式都使用嵌套参数并将解析:例如, `blog/page-2/`将导致`blog_articles`与两个位置参数匹配:`page-2/`和`2`。第二个模式`comments`将匹配`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不查看请求方法。换句话说,所有的请求方法- ,,`POST` 等-将被路由到相同的URL相同的功能。`GET``HEAD` ## 指定视图参数的默认值 一个方便的技巧是为视图的参数指定默认参数。这是一个示例URLconf和视图: ``` # URLconf from django.urls import path from . import views urlpatterns = [ path('blog/', views.page), path('blog/page/', 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`捕获的任何值。 ## 表现 a中的每个正则表达式在`urlpatterns`第一次访问时编译。这使得系统非常快。 ## `urlpatterns`变量的语法 `urlpatterns`应该是Python列表`path()`和/或 `re_path()`实例。 ## 错误处理 当Django找不到所请求URL的匹配项时,或者引发异常时,Django会调用错误处理视图。 用于这些情况的视图由四个变量指定。它们的默认值应该足以满足大多数项目的需要,但可以通过覆盖它们的默认值来进一步自定义。 有关完整详细信息,请参阅有关[自定义错误视图](https://docs.djangoproject.com/en/2.0/topics/http/views/#customizing-error-views)的文档。 可以在根URLconf中设置此类值。在任何其他URLconf中设置这些变量将不起作用。 值必须是callables或字符串,表示应该调用以处理手头错误条件的视图的完整Python导入路径。 变量是: - `handler400` - `handler403` - `handler404` - `handler500` ## 包括其他的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//', 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('-/history/', views.history), path('-/edit/', views.edit), path('-/discuss/', views.discuss), path('-/permissions/', views.permissions), ] ``` 我们可以通过仅指定公共路径前缀一次并对不同的后缀进行分组来改进这一点: ``` from django.urls import include, path from . import views urlpatterns = [ path('-/', 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('/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。 ## 传递额外选项来查看功能 URLconfs有一个钩子,允许您将额外的参数作为Python字典传递给视图函数。 该`path()`函数可以采用可选的第三个参数,该参数应该是传递给视图函数的额外关键字参数的字典。 例如: ``` from django.urls import path from . import views urlpatterns = [ path('blog//', 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//', views.year_archive, name='news-year-archive'), #... ] ``` 根据这种设计,对应于年度归档文件的URL *NNNN* 是`/articles//`。 您可以使用以下方法在模板代码中获取这些: ``` 2012 Archive {# Or with the year in a template context variable: #} ``` 或者在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和大多数第三方应用程序的部分假定此视图具有名称的URL模式 `login`。如果你有一个自定义登录查看,并给它的URL名称`login`, `reverse()`将只要它在找到你的自定义视图 `urlpatterns`之后,`django.contrib.auth.urls`包括(如果这是包含在所有)。 如果参数不同,您也可以对多个URL模式使用相同的名称。除URL名称外,还`reverse()`匹配参数的数量和关键字参数的名称。 ## URL命名空间 ### 介绍 即使不同的应用程序使用相同的URL名称,URL命名空间也允许您唯一地反转。对于第三方应用程序来说,始终使用命名空间URL是一种很好的做法(正如我们在教程中所做的那样)。同样,如果部署了多个应用程序实例,它还允许您反向URL。换句话说,由于单个应用程序的多个实例将共享命名URL,因此命名空间提供了一种将这些命名URL分开的方法。 正确使用URL命名空间的Django应用程序可以针对特定站点多次部署。例如,[`django.contrib.admin`]有一个 [`AdminSite`]类允许您轻松 部署多个admin实例。在后面的示例中,我们将讨论在两个不同位置从教程部署民意调查应用程序的想法,以便我们可以为两个不同的受众(作者和发布者)提供相同的功能。 URL命名空间分为两部分,两部分都是字符串: - 应用命名空间 这描述了正在部署的应用程序的名称。单个应用程序的每个实例都具有相同的应用程序命名空间。例如,Django的管理应用程序具有可预测的应用程序命名空间`'admin'`。 - 实例命名空间 这标识了应用程序的特定实例。实例名称空间在整个项目中应该是唯一的。但是,实例名称空间可以与应用程序名称空间相同。这用于指定应用程序的默认实例。例如,默认的Django管理实例的实例名称空间为`'admin'`。 命名空间URL使用`':'`运算符指定。例如,使用引用管理应用程序的主索引页面`'admin:index'`。这表示名称空间`'admin'`和命名URL `'index'`。 命名空间也可以嵌套。命名URL `'sports:polls:index'`将查找`'index'`在命名空间中命名的模式,该模式`'polls'`本身在顶级命名空间中定义`'sports'`。 ### 反转命名空间的URL 当给出`'polls:index'`要解析的命名空间URL(例如)时,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('/', 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的应用程序命名空间可以用两种方式指定。 首先,您可以`app_name`在包含的URLconf模块中设置属性,该属性与属性处于同一级别`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('/', views.DetailView.as_view(), name='detail'), ... ] ``` urls.py ``` from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), ] ``` 定义的URL `polls.urls`将具有应用程序命名空间`polls`。 其次,您可以包含一个包含嵌入式命名空间数据的对象。如果`include()`是列表[`path()`](https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.path)或 [`re_path()`](https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.re_path)实例,则该对象中包含的URL将添加到全局命名空间。但是,您还可以`include()`使用包含以下内容的2元组: ``` (, ) ``` 例如: ``` from django.urls import include, path from . import views polls_patterns = ([ path('', views.IndexView.as_view(), name='index'), path('/', views.DetailView.as_view(), name='detail'), ], 'polls') urlpatterns = [ path('polls/', include(polls_patterns)), ] ``` 这将在指定的应用程序命名空间中包含指定的URL模式。 可以使用`namespace`参数to 指定实例名称空间[`include()`](https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.include)。如果未指定实例名称空间,则它将默认为包含的URLconf的应用程序名称空间。这意味着它也将是该命名空间的默认实例。