django-url调度器-初级篇

  Django 遵从 MVC 模型,并将其特色化为 MTV 模型。模型的核心是通过用户访问的 url 来指向处理的函数,而函数处理后返回相应的结果。所以url决定了用户访问的入口,另外表单处理的提交地址也需要指定的url。url是所有功能的入口,所以url的编写就变得非常重要。

  Django 的 url 编写涉及了 python 的 re 模块,也就是正则表达式,这部分内容需要提前掌握。

  本篇的内容将结合官方的1.8.2的文档进行说明,如果有说明不清的地方可以相应参照官方的文档,我这里提供一个进行中文翻译后的:戳这里

  在进行编写的说明前,我先介绍一下django是如何处理一个请求的:

  1.用户发来一个请求。Django将用户的请求报文等信息封装成HttpRequest对象,然后经过各种中间件处理后,抵达 url 模块进行处理函数的选择。

  2.Django要决定使用哪个模块用作匹配,这个通常由 settings.py 中的 ROOT_URLCONF 的值决定,例如:ROOT_URLCONF = ‘test_web.urls‘ 。就表示将使用 test_web(项目同名app) 这个 app 下的 urls 这个模块文件( 这个模块也称为url的根模块,可修改 )。但如果进来的HttpRequest对象具有一个 urlconf  属性(通过中间件 request processing  设置),则使用这个值来替换 ROOT_URLCONF  设置。(可能会存在版本差异)

  3.Django 加载该 Python 模块并寻找可用的 urlpatterns 变量。它是一个 Python 列表,里面的元素是 django.conf.urls.url() 的实例。

  4.Django 按照正则匹配的方式,依次匹配每个URL 模式,在第一个与请求的URL 匹配的地方停下来(下面也符合的会被忽视)。

  5.一旦其中的一个正则表达式匹配上,Django 将导入并调用给出的视图,它是一个简单的Python 函数(或者一个基于类的视图)。视图将获得如下参数:

    a)  一个HttpRequest 实例(这也是为什么 view 函数的第一个参数要是 request,该实例封装了所有的 http 请求报文的信息)

    b) 如果正则匹配的 url 中使用了括号分组,但却没有为分组进行命名,则使用位置参数的模式为view函数传参。

    c) 如果是命名的分组,则使用关键字传参的方式。但是可以被django.conf.urls.url()的可选参数kwargs覆盖。

  6.如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Django 将调用一个适当的错误处理视图。

  7.函数处理完毕,返回处理后的结果。


官方手册的例子:

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

分析:

  1.若要从 URL 中捕获一个值,只需要在它周围放置一对圆括号。(即正则中的分组匹配)

  2.不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。(django自动在域名后添加了/,这个默认行为可以进行改写)

  3.每个正则表达式前面的‘r‘ 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义。参见Dive Into Python 中的解释。

一些请求的例子:

  /articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, ‘2005‘, ‘03‘)。

/articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。

/articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的情况来探测匹配的次序。

/articles/2003 不匹配任何一个模式,因为每个模式要求URL 以一个斜线结尾。

   /articles/2003/03/03/ 将匹配最后一个模式。Django 将调用函数views.article_detail(request, ‘2003‘, ‘03‘, ‘03‘)。


命名组

  上面的例子中,虽然实现了参数的传递,但是并没有我们熟知的关键字传参。要使用关键字传参,只有为分组命名就行了。例如:(?P<name>\d+),这个分组表示匹配一个或多个任意的数字,并以 name = 匹配到的数字,如 name = ‘123‘ 的方式传给view 函数。

  但是,要注意一点,url 捕获的所以参数都是字符串类型,虽然 \d 在正则中表示匹配数字,但传参的时候,传的是字符串。例如,正则捕获的 123 ,但传参是 ‘123‘。

官方例子

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.否则,它将以位置参数传递所有的非命名参数。

  根据传递额外的选项给视图函数(下文),这两种情况下,多余的关键字参数也将传递给视图。

注意:

  1.一条 url 中,分组不能同名,否则报错。(初步测试)

  2.所谓的有命名分组就使用命名参数,忽略非命名参数是下面这样的:

url(r‘add/(\d+)/(?P<num1>\d+)/(?P<num2>\d+)/‘, add, name=‘add‘),
def add(request, num1, num2):
    num1 = int(num1)
    num2 = int(num2)
    return HttpResponse(num1 + num2)

  在这里,request 是 Httprequest,是 django 自动传递的,我们只要看 num1 和 num2 两个参数就可以的。这里我的处理函数除了 request 之外还需要 2 个参数,但是我在 url 中使用了三个分组,理论上应该会捕获 3 个参数。

  但是,当我访问 http://127.0.0.1:8000/add/666/321/123/  时,我得到的结果是:

  

  另外,因为捕获的参数是字符串类型, 所以我使用了 int() 函数进行类型转换,如果不这样的话:

def add(request, num1, num2):

    return HttpResponse(num1 + num2)

得到的结果就是:

  字符串的拼接,所以说,捕获的参数都是字符串

  好了,回到正题。我的函数需要除了 request 之外的 2 个参数,但是我在 url 中捕获了三个,得到的结果是后面的两个命名组的参数,也就是多出来的被忽略了

  这就是所谓的当命名组存在的时候,非命名组会被忽略。

  但是,我的 url 是这样写的:

 url(r‘add/(\d+)/(?P<num2>\d+)/‘, add, name=‘add‘),

  我希望前面的未命名组按位置传给 num1 而 num2 使用关键字参数。

  现在,我访问: http://127.0.0.1:8000/add/321/123/

  报错的信息是,函数需要 3 个参数,而我们给了 2 个,其中,去除自动传递的 request,也就是我们只捕获到了 1 个参数。

  此时,再看看这句活:当命名组存在时,会忽略非命名组

  因为非命名组捕获的参数被忽略了,所以才导致我们少传了一个参数。

  这个时候,你应该知道这里的忽略是什么意思了吧。


URLconf 在什么上查找

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

  例如,http://www.example.com/myapp/请求中,URLconf 将查找myapp/。

   在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。

  URLconf 不检查使用了哪种请求方法。换句话讲,所有的请求方法 —— 即,对同一个URL的无论是POST请求、GET请求、或HEAD请求方法等等 —— 都将匹配到相同的函数。

  但是,我们能限制某个函数只能由某种方式访问,但这里不是 url 这里的内容了,以后再讲。


捕获的参数永远是字符串

  关于这句话我在刚才的 num1 和 num2 相加的示例中已经演示过了,这里记住这句话就行了。


指定视图参数的默认值

  这并不是 django 特有的用法,这是 python中 的函数默认参数的内容。但是django这里能处理一些特殊的情况:

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r‘^blog/$‘, views.page),
    url(r‘^blog/page(?P<num>[0-9]+)/$‘, views.page),]
def page(request, num="1"):
    ......
    return .....

  在上面的例子中,两个URL模式指向同一个视图views.page —— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,page() 函数将使用num参数的默认值"1"。如果第二个模式匹配,page() 将使用正则表达式捕获的 num 值。


性能

  urlpatterns 中的每个正则表达式在第一次访问它们时被编译。这使得系统相当快。


urlpatterns 变量的语法

  urlpatterns 应该是一个 python 列表,列表中存放的都是 url() 的实例。


错误处理

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

   这些情况发生时使用的视图通过4个变量指定。它们的默认值应该满足大部分项目,但是通过赋值给它们以进一步的自定义也是可以的。

  完整的细节请参见自定义错误视图。

  这些值可以在你的根URLconf 中设置。在其它URLconf 中设置这些变量将不会生效果。

  它们的值必须是可调用的或者是表示视图的Python 完整导入路径的字符串,可以方便地调用它们来处理错误情况。

这些值是:

handler404 —— 参见django.conf.urls.handler404。

handler500 —— 参见django.conf.urls.handler500。

handler403 —— 参见django.conf.urls.handler403。

handler400 —— 参见django.conf.urls.handler400。

 

 关于这部分我目前也在研究中,以后研究出结果再分享出来。

时间: 2024-10-11 03:02:00

django-url调度器-初级篇的相关文章

django-url调度器-中级篇

在初级篇中,我们接触了: 1.url 的简单编写 2.两种传参的方式 3.捕获的参数总是字符串 4.为视图设置默认参数 …… 在中级篇中将更进一步. 包含其它的URLconfs 当网站非常大的时候,将所有的url都写在一个url模块中会非常的臃肿,且后期不便于维护.此时,就可以使用包含的方式将部分的url放在另一个url模块中.最常见的就是每个app的url都进行分离. 官方代码示例: from django.conf.urls import include, url urlpatterns =

django-url调度器-高级篇

我们在中级篇中学会了如何进行反向解析,但是有这样一个问题,在为 url 命名的时候,名字不能重复,否则会导致各种各样的问题.在 url 还少的时候保证不重名还是比较简单的,但是 url 多起来以后就比较难了.为了解决这样的问题,可以在 url 中加一个前缀.例如,我有一个 url 的名字叫做 'comment' ,此时,我可以为其加一个前缀,这个前缀通常是 app 名,例如:'myapp-comment'. 这也是django所推荐的命名方式,但是这样始终是治标不治本.此时,我们就要学习 dja

django url调度

Django的url配置同样遵循着DRY(dont repeat yourself)的规则.以下都是官方文档的例子: 首先介绍的是Django如何处理http的请求: 1.在setting里定义ROOT_URLCONF ,这个值就是url的根配置,但若被request processing中间件定义了HttpRequest的urlconf属性,会替换掉ROOT_URLCONF 2.Django 加载模块,寻找 urlpatterns,它是pattern函数的返回值,是url的list 3.寻找每

ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL

ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL 引言--- 在现今搜索引擎制霸天下的时代,我们不得不做一些东西来讨好爬虫,进而提示网站的排名来博得一个看得过去的流量. URL重写与优化就是搜索引擎优化的手段之一. 假如某手机网站(基于ASP.NET MVC)分类页面URL是这样的, http://www.xxx.com/category/showcategory?categoryid=1000&view=list&orderby=price&p

FreeRTOS高级篇3---启动调度器

使用FreeRTOS,一个最基本的程序架构如下所示: int main(void) { 必要的初始化工作; 创建任务1; 创建任务2; ... vTaskStartScheduler(); /*启动调度器*/ while(1); } 任务创建完成后,静态变量指针pxCurrentTCB(见<FreeRTOS高级篇2---FreeRTOS任务创建分析>第7节内容)指向优先级最高的就绪任务.但此时任务并不能运行,因为接下来还有关键的一步:启动FreeRTOS调度器. 调度器是FreeRTOS操作系

Django Rest Framework url注册器组件 | 响应器组件 | 分页器组件

文章参考博主:https://www.cnblogs.com/li-li/p/10103918.html 1.url注册器组件 : 通过DRF的视图组件,数据接口逻辑被我们优化到最后剩下一个类,接下来,我们使用DRF的url控制器来帮助我们自动生成url '''3.使用url注册器组件的url''' #导入模块 from rest_framework import routers router = routers.DefaultRouter() # 3.将需要自动生成url的接口注册到route

Django学习【第1篇】:Django之MTV模型

Django框架第一篇基础 一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model(模型):和数据库相关的,负责业务对象与数据库的对象(ORM) Template(模板):放所有的html文件 模板语法:目的是将白变量(数据库的内容)如何巧妙的嵌入到html页面中 View(视图):负责业务逻辑,并在适当的时候调用Model和Template 此外,Django还有一个URL分发

Django使用Channels实现WebSocket--下篇

希望通过对这两篇文章的学习,能够对Channels有更加深入的了解,使用起来得心应手游刃有余 通过上一篇<Django使用Channels实现WebSocket--上篇>的学习应该对Channels的各种概念有了清晰的认知,可以顺利的将Channels框架集成到自己的Django项目中实现WebSocket了,本篇文章将以一个Channels+Celery实现web端tailf功能的例子更加深入的介绍Channels 先说下我们要实现的目标:所有登录的用户可以查看tailf日志页面,在页面上能

DJango — URL的Reverse和Resolve

DJango系列的上一篇我们讲到了它是怎么解析和匹配URL的,并从URL中提取一些有用的信息(曾以year和month为例);但是,URL的管理仍然是一个巨大的工程,我们不得不维护数量庞大的pattern,即使有正则表达式的支持.另一方面,URL数量的增大也将带来匹配和解析正确性的考验.这一篇我们会进一步深入URL的学习,并掌握Reverse和Resolve. 一:Reverse和Resolve的作用我们可以为某一个url映射定义一个名字,称之为url_name,这样有什么用呢?在此之前我们先介