django的url配置

在一个请求到达的时候,最先达到的就是视图层,然后根据url映射到视图函数。这一部分我们来说明url的配置。

概述

为了给一个应用设计URL,你需要创建一个Python 模块,通常称为URLconf(URL configuration)。 这个模块是纯粹的Python 代码,包含URL 模式(简单的正则表达式)到Python 函数(你的视图)的简单映射。

映射可短可长,随便你。 它可以引用其它的映射。 而且,因为它是纯粹的Python 代码,它可以动态构造。

django如何处理请求

当一个用户请求Django 站点的一个页面,下面是Django 系统决定执行哪个Python 代码遵循的算法:

  1. Django 决定要使用的根URLconf 模块。 通常,这是ROOT_URLCONF设置的值,但是如果传入的HttpRequest对象具有urlconf属性(由中间件设置),则其值将被用于代替ROOT_URLCONF设置。
  2. Django 加载该Python 模块并寻找可用的urlpatterns它是django.conf.urls.url() 实例的一个Python 列表。
  3. Django 依次匹配每个URL 模式,在与请求的URL 匹配的第一个模式停下来。
  4. 一旦正则表达式匹配,Django将导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的class-based view)。 视图将获得如下参数:
    • 一个HttpRequest 实例。
    • 如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图。
    • 关键字参数由正则表达式匹配的命名组组成,但是可以被django.conf.urls.url()的可选参数kwargs覆盖。
  5. 如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Django 将调用一个适当的错误处理视图。

在官网上有一个实例和说明,来说明url是怎么匹配的,如下:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

#需要注意的是:
若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。 #参照请求实例的第一个和最后一个。
不需要添加一个前导的反斜杠,因为每个URL 都有。 例如,应该是^articles 而不是 ^/articles。
每个正则表达式前面的'r' 是可选的但是建议加上。 它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义。

#一些请求实例

    /articles/2005/03/ 请求将匹配列表中的第三个模式。 Django 将调用函数views.month_archive(request, '2005', '03')。
    /articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。
    /articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。 请像这样自由插入一些特殊的情况来探测匹配的次序。 这里,Django会调用函数views.special_case_2003(request)
    /articles/2003 不匹配任何一个模式,因为每个模式要求URL 以一个斜线结尾。
    /articles/2003/03/03/ 将匹配最后一个模式。 Django 将调用函数views.article_detail(request, '2003', '03', '03')。

命名组

上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。 在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。

在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。 像这样:


  • /articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')
  • /articles/2003/03/03/ 请求将调用函数views.article_detail(request, year='2003', month='03', day='03')

需要注意的是,无论捕获的参数是什么类型,总是作为字符串传递给视图函数。譬如上面捕获了年份为整型,但是仍然是作为字符串传递的。

匹配/分组算法

下面是URLconf 解析器使用的算法,针对正则表达式中的命名组和非命名组:

  1. 如果有命名参数,则使用这些命名参数,忽略非命名参数。
  2. 否则,它将以位置参数传递所有的非命名参数。

URLconf的查找

请求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。 进行匹配时将不包括GET或POST请求方式的参数以及域名。

例如,在https://www.example.com/myapp/的请求中,URLconf将查找myapp/

https://www.example.com/myapp/?page=3的请求中,URLconf将查找myapp/

URLconf 不检查使用了哪种请求方法。 换句话说,所有请求方法 - POSTGETHEAD - 将路由到同一个URL的相同功能。

通过一个实例,来说明上面的参数传递:

url映射如下:
    url(r'^sign/([0-9]{4})/([0-9]{2})/$', sign),                   #传递位置参数
    url(r'^sign/(?P<year>[0-9]{4})/(?P<mon>[0-9]{2})/(?P<day>[0-9]{2})/$', sign),            #传递关键字参数

#视图函数如下:
def sign(request, year, mon, day="02"):              #需要形参来接收url传递过滤的实参
    return render(request, "sign.html", {"year": year, "month": mon, "day": day})

#前端代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试参数传递</title>
</head>
<body>
   <h3>年份是: {{ year }}</h3>
   <h3>月份是:{{ month }}</h3>
   <h3>多少号:{{ day }}</h3>
</body>
</html>

错误处理

当Django 找不到一个匹配请求的URL 的正则表达式时,或者当抛出一个异常时,Django 将调用一个错误处理视图。

这些情况发生时使用的视图通过4个变量指定。 它们的默认值足以满足大多数项目,但可以通过覆盖其默认值进一步进行自定义。

Django中默认的错误视图对于大多数web应用已经足够了,但是如果你需要任何自定义行为,重写它很容易。 只要在你的根URLconf中指定下面的处理器(在其他任何地方设置它们不会有效)。

handler404覆盖了page_not_found()视图:
handler404 = 'mysite.views.my_custom_page_not_found_view'
handler500覆盖了server_error()视图:
handler500 = 'mysite.views.my_custom_error_view'
handler403覆盖了permission_denied()视图:
handler403 = 'mysite.views.my_custom_permission_denied_view'
handler400覆盖了bad_request()视图:
handler400 = 'mysite.views.my_custom_bad_request_view'

URL的扩展

当一个django工程中有多个app应用时,我们可以为每一个app单独设置其对应的url映射,然后再把对应app的urls.py文件包含在根urlconf中即可。

urlpatterns = [
    url(r'^test', include("app01.urls")),
    url(r'^bk', include("backend.urls")),
    url(r'^cmdb', include("cmdb.urls")),
]

#我们只需要在对应的app中定义urls.py文件即可,文件内容和根ruls.py文件类似。
#在根urlconf中捕获的任何参数,都可以传递给对应的子urlconf,进而可以传递给对应的视图函数。

URL传递额外的参数

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]


#这个实例中不仅传递了关键字参数year,还传递了后面大括号中的关键字残血foo="bar",

url中使用include包含子url映射时,用法一样,可以直接跟在父url映射后,也可以直接跟在子url映射后面。

URL反向解析

在 Django 项目中经常需要获取最终形式的 URL,这么做是为了在生成的内容中嵌入 URL(视图和素材资源网址,呈现给用户的网址,等等), 或者用于在服务器端处理导航流程(重定向等)

此时,一定不能硬编码 URL(费时、不可伸缩,而且容易出错), 或者参照 URL 配置创造一种生成 URL 的机制,因为这样非常容易导致线上 URL 失效。

换句话讲,我们需要的是一个 DRY 机制。 这种机制的一个优点是,当改进 URL 设计之后无需在项目源码中大范围搜索、替换失效的 URL。

Django 提供了一种方案,只需在 URL 映射中设计 URL。 我们为其提供 URL 配置,然后就可以双向使用:

  • 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
  • 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

第一种方式是我们在前面的章节中一直讨论的用法。 第二种方式叫做反向解析URL反向URL匹配反向URL查询或者简单的URL反查

在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url 模板标签。
  • 在Python代码中:使用reverse()函数。
  • 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

上面摘自官网,直白一点,在form表单提交的时候action指向,我们不用再使用直接的url方式,而是在urlconf中给映射定义一个名字,然后再form表单中使用这个名字。有点就是当url映射关系更改时,只要名字不变,我们的form表单就不用更改。

一个简单的实例应用如下:

#url映射如下
url(r'^main/', main, name="enter_site"),

#html代码中form提交如下:
<form action="{% url "enter_site" %}" method="post">

#注意格式的写法,名字要加上双引号。

在视图函数中,return返回的时候,要么返回的HttpResponse对象,要么返回的是经过render渲染过的html代码文件,还可以返回HttpResponseRedirect对象,指向一个url,而这个url就是在urlconf中配置的url,因此这里引用的时候我们可以直接返回url,也可以通过reverse函数返回。

urlconf中配置如下:
url(r'^info/', info, name="list_info"),

在视图函数中引用如下:
第一种直接引用url:
return HttpResponseRedirect("/info/")
第二种使用reverse函数:
from django.urls import reverse
return HttpResponseRedirect(reverse("list_info"))

#这两种方法的返回是一样的,推荐使用第二种。

使用name还有一个好处就是,我们知道在url解析时,可能有多个url可以指向一个视图,这是可以的,但是在反解析时,就会出问题了同一个视图有两个结果进行匹配。因此我们引入了name函数,给每一个url定义一个名字,在反解析时使用名字即可。

上面提到过在一个django工程中可能会有很多app,每个app下的url映射可能是重名的,这样即便定义了name(因为name重名)也会出问题,因此引入了命名空间的概念。

以下实例:

#根urlconf配置
urlpatterns = [
    url(r'^mysite/', include("mysite.urls", namespace="mysite")),

]

#mysite应用中url配置
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^main/', main, name="enter_site"),
    url(r'^info/', info, name="list_info"),
    url(r'^sign/([0-9]{4})/([0-9]{2})/$', sign),
    url(r'^sign/(?P<year>[0-9]{4})/(?P<mon>[0-9]{2})/(?P<day>[0-9]{2})/$', sign),
]

#form表单中url配置
 <form action="{% url "mysite:enter_site" %}" method="post">
#注意这里的格式,命名空间与url名字之间用冒号隔开。

#视图函数中的应用
return HttpResponseRedirect(reverse("mysite:list_info"))
原文地址:https://www.cnblogs.com/wxzhe/p/10313675.html