Django 处理HTTP请求


当前第2页 返回上一页

这可用于从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从父URLconfs接收任何捕获的参数,因此以下示例有效:

# 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。

传递额外的选项来查看函数

URLconfs有一个钩子,可让您将额外的参数作为Python字典传递给视图函数。

该path()函数可以使用可选的第三个参数,该参数应该是传递给view函数的额外关键字参数的字典。

例如:

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查找中的其他信息。

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

根据这种设计,对应于年度归档文件的URL NNNN 是/articles//。

您可以使用以下模板代码获取它们:

<a >2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a >{{ 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和大多数第三方应用程序的某些部分假定此视图具有名称为的URL模式 login。如果你有一个自定义登录查看,并给它的URL的名字login, reverse()会发现自定义视图,只要它在 urlpatterns以后django.contrib.auth.urls包括(如果这是包含在所有)。

如果多个URL模式的参数不同,也可以使用相同的名称。除URL名称外,还要reverse() 匹配参数数量和关键字参数的名称。

URL命名空间

简介

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

对于特定站点,可以多次使用正确使用URL名称空间的Django应用程序。例如,django.contrib.admin 有一AdminSite类允许您 部署多个admin实例。在下一个示例中,我们将讨论从教程在两个不同位置部署民意调查应用程序的想法,以便我们可以为两个不同的受众(作者和发布者)提供相同的功能。

URL名称空间分为两部分,都是字符串:

  • 应用程序名称空间这描述了正在部署的应用程序的名称。单个应用程序的每个实例将具有相同的应用程序名称空间。例如,Django的admin应用程序具有可预测的应用程序名称空间'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')),
]

民调/的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的应用程序名称空间。

首先,您可以app_name在包含的URLconf模块中设置与该urlpatterns属性相同级别的属性。您必须将实际模块或对该模块的字符串引用传递给include(),而不是其urlpatterns自身的列表。

民调/的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将具有一个应用程序名称空间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的应用程序名称空间。这意味着它将也是该名称空间的默认实例。

详细参考: https://docs.djangoproject.com/en/3.0/topics/http/urls/



标签:Django

返回前面的内容

相关阅读 >>

基于类的视图

Django 处理http请求

基于类的视图简介

部署清单

Django 模板

部署静态文章

错误报告

Django 的性能与优化

使用基于类的视图进行表单处理

使用asgi进行部署

更多相关阅读请进入《Django》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...