1.URL路由系统前言

URL是Web服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的URL地址,然后被响应。

在Django项目中编写路由,就是向外暴露我们接收哪些URL的请求,除此之外的任何URL都不被处理,也没有返回。通俗地理解,不恰当的形容,URL路由是你的Web服务对外暴露的API。

Django奉行DRY主义,提倡使用简洁、优雅的URL,没有.php或.cgi这种后缀,更不会单独使用0、2097、1-1-1928、00这样无意义的东西,让你随心所欲设计你的URL,不受框架束缚。

2. URL简介

路由的分解:

  URL路由在Django项目中的体现就是urls.py文件,这个文件可以有很多个,但绝对不会在同一目录下。实际上Django提倡项目有个根urls.py,各app下分别有自己的一个urls.py,既集中又分治,是一种解耦的模式。

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

当我们新建一个项目的时候,在项目根文件中,会自动默认生成一个urls.py的路由文件。

3. URLconf配置

当客户端发送发送到一个指定的URL地址的请求时,会首先进入Django内部,然后根据,导入django.urls.path()或者django.urls.re_path()的urlpatterns,依次匹配每个URL模式,在与请求的URL相匹配的第一个模式停下来。也就是说,url匹配是从上往下的短路操作,所以url在列表中的位置非常关键。

格式:

from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/', views.test),
url(r'^upload/$', views.upload),
] # 大白话的基本格式:
from django.conf.urls import url urlpatterns = [
url(正则表达式, views视图函数,参数,别名),    # 下面从这四个位置来一一说明
]

参数说明:

  • 正则表达式:一个正则表达式字符串(其实就是客户端请求的URL地址)
  • views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 参数:可选的要传递给视图函数的默认参数(字典形式)
  • 别名:一个可选的name参数

3.1 正则表达式详解

基本配置

# 位置参数
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),
]

4个注意事项

  1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  3. 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  4. 每个正则表达式前面的'r' 是可选的但是建议加上。

请求的URL与路由系统中的URLcnfo匹配的是哪部分?

说明,请求的URL是被当做一个普通的字符串,传递给Django(Django中的URLconf部分)的。那到底是URL上的哪部分字符串被拿来与URL系统对应起来呢?

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

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

URLconf不检查使用何种HTTP请求方法,所有请求方法POST、GET、HEAD等都将路由到同一个URL的同一个视图。在视图中,才根据具体请求方法的不同,进行不同的处理,这里的就是后台开发者的工作。

与正则表达式相关的补充

# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True

Django settings.py配置文件中默认没有设置 APPEND_SLASH 这个参数,但 在Django中是 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址(URL地址)的结尾加 '/' 。其效果如下:

假设我们定义了一个urls.py如下:

from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'^blog/$', views.blog),
]

当我们访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example.com/blog/ 。

如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时,网址后面不会自动帮我们加入斜杠 ‘ / ’ ,那就会提示找不到页面。

3.1 正则表达式详解(续)

例如:基本配置的例子中,正则表达式分组匹配(通过圆括号)来捕获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),
]

可以通过位置参数和关键字参数进行对比结果的来看,关键字参数就是在位置参数的匹配字符前面多加了 " ?P<name> " 而已。

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

例如,针对url /articles/2017/12/相当于按以下方式调用视图函数:

views.month_archive(request, year="", month="")

在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

至于究竟应该使用哪一种,你可以根据自己的喜好来决定。

根据之前所学习的知识,现在可以总结出来,Django框架通过URL地址,可以传递的值有三种形式:

1.   通过模板文件中的web请求,构造带有参数的URL地址、

    在斜杠后面加入问号,和关键词的key和value:

    例如:http://www.example.com/myapp/?page=3

    这里urls.py中对应的URL为 ‘ /myapp/ ’ ,page为参数,3为参数的值,这里的参数关键词,不是来自urls.py里面的对应关系

2.  通过urls.py文件中的正则表达式,将参数作为位置参数专递给视图函数。      

    例如:http://www.example.com/myapp/2016/11

    这里urls.py中对应的URL正则为 ‘ /myapp/ ([0-9]{4})/([0-9]{2})/$ ‘

    views.py视图中的对应函数接收参数形式为:

        def myapp(request, arg1, arg2) : …………

    这里啰嗦一下位置参数的一些概念,例如上面arg1和arg2这两个接收参数的变量名称是可以随便改的,但是最终还是第一个参数接收的值是2016,第二接收的值是11。

3.  通过urls.py文件中的正则表达式,将参数作为关键词参数专递给视图函数

    例如:http://www.example.com/myapp/2017/12

    这里urls.py中对应的URL正则为 ‘ /myapp/ (?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$ ’

‘    views.py视图中的对应函数接收参数形式应该为:

        def myapp(request, year, month) : ………

        或者

        def myapp(request,month, year) : ………

    可以看到,只要视图函数接收的参数的名称与urls路由文件中的,关键词参数名称,year和month一样,不管是month在前,还是year在前,都是一样可以或得到:year = 2017,month = 12

注意、注意、注意:位置和关键字不能混用!!!!!!!!!!!!!

  下面这个是url对应关系错误的写法:

    例如:前面一个是位置参数,最后是关键字参数。反过来也不行!

    url(r'^articles/([0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),

捕获的参数永远都是字符串

每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

传递到视图函数views.year_archive() 中的year 参数永远是一个字符串类型。

视图函数中可以指定默认值

# urls.py中
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),
] # views.py中,可以为num指定默认值
def page(request, num=""):
pass

在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

include其他的URLconfs

#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones. #For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs: from django.conf.urls import include, url urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件
]

3.2 views视图函数

urlpatterns 中的第二个位置就是与U正则表达式中的URL地视图 形成映射关系的视图函数了。
前面已经讲过了视图系统的各种使用了。视图系统请点击我 >>>>
因为视图函数都是写在一个APP中的views.py视图文件里面,所以,我们需要先导入APP中的views视图文件模块,如下:

from app01 import views      # 假设我们的APP命名为app01

urlpatterns = [
url(r'^blog_list/$', views.blog_list),
url(r'^blog_list/page(?P<num>[0-9]+)/$', views.blog_list),
]

然后在url对应关系上,的视图函数关系就是:“ views(视图名).对应的视图函数名 ”

视图函数中指定默认值

# urls.py中
from django.conf.urls import url
from app01 import views      # 假设我们的APP命名为app01 urlpatterns = [
url(r'^blog_list/$', views.blog_list),
url(r'^blog_list/page(?P<num>[0-9]+)/$', views.blog_list),
]
# views.py中,可以为num指定默认值为10
def blog_list(request, num=""):
pass

在上面的例子中,两个URL模式指向相同的view - views.blog_list- 但是第一个模式并没有从URL中捕获任何东西。

如果第一个模式匹配上了,blog_list()函数将使用其默认参数num=“10”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

include其他的URLconf

#At any point, your urlpatterns can “include” other URLconf modules. Thi#essentially “roots” a set of URLs below other ones.
#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs: from django.conf.urls import include, url urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件
]

3.3 参数(了解)

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

django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。例如:

from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
] # {'foo': 'bar'}就是额外传参的一个参数,参数可以有很多key和value组成一个词典

3.4 别名

url对应关系,加入别名的写法如下:
from django.conf.urls import url
from . import views urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}, name='myblog'),
]
  # 可以看出 myblog 就是这个url地址对应关系的别名了

怎么起别名?
在url匹配模式中,定义name="别名"

更多别名的应用请看下面的命名URL和URL反向解析

4. 命名URL和URL反向解析

Django 提供一个办法可以让URL 映射到对应的视图中,通过视图上对应的视图函数做相关的业务逻辑运算。此时Django中的URLconf,是可以双向使用它的:

  • 根据用户/浏览器发起的URL 请求,它调用正确的对应的Django 视图,并从URL 中提取它的参数需要的值,进入到视图函数。这个过程是之前一直讨论的,这也可以说是正向的URL。
  • 当根据Django 视图的标识和将要传递给某个视图函数的参数的值,来获取到与之关联的URL的过程,就是URL的反向解析。

简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。

这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。

举个简单的例子:

# urls.py 文件这样写
url(r'^home', views.home, name='myhome'), # 给我的url匹配模式起名为 myhome
url(r'^index/(\d*)', views.index, name='myindex'), # 给我的url匹配模式起名为myindex

4.1 模板里的应用场景(myhome做例子)

  首先,在视图函数(home)做个转场过度一下:

def home(request):
return render(request, "myhome.html")

  其次,在模板里面的myhome.html可以这样引用:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% url 'myhome' %}      <!--得到一个URL,但是url是字符串形式的哦-->
</body>
</html>
# 格式:{% url '别名'%}

  最后,结果响应返回到浏览器为:

4.2 直接在views函数的使用的应用场景(myindex做例子)

首先,直接在views函数中这样引用:

from django.urls import reverse # 一样要引入urls中的reverse
def index(request,num): #num是url中的参数
ret = reverse('myindex',args=(num,))  # 通过reverse函数,并根据url上的别名,就可以反向获取到URL字符串
return HttpResponse(ret)
# 格式为reverse('url别名', 参数)

最后,结果如下:

例子:思考下面的例子
第一步:URLconf写成如下:

from django.conf.urls import url
from . import views urlpatterns = [
# ...
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
# ...
]

根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/。

第二步,如何写视图函数year_archive?

……………………

第三步,模板中的引入写法,你可以在模板的代码中使用下面的方法获得它们:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

在Python 代码中,这样使用:

from django.urls import reverse
from django.shortcuts import redirect def redirect_to_year(request):
# ...
year = 2006
# ...
return redirect(reverse('news-year-archive', args=(year,)))

如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

注意:

为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL 的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python 名称。

当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。

在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment。

4.3 如果RUL有参数的话,如何使用URL反向解析?

1. 模板语言中:
  {% url "别名" 2018 "nb" %}

2. 视图函数中

  传位置参数:

    reverse("别名", args=(2018, "nb")) 

5. URL的命名空间模式

要给Django项目可能会有很多个APP,而根据上面的路由分解思路,不同的APP里面都会有urls.py的路由分系统,但是可以出现不同APP可能会使用相同的URL名称,所以,URL的命名空间模式也可以让你唯一反转命名的URL。

举个例子:

project中的urls.py

from django.conf.urls import url, include

urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]

app01中的urls.py

from django.conf.urls import url
from app01 import views app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

app02中的urls.py

from django.conf.urls import url
from app02 import views app_name = 'app02'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

语法:

'命名空间名称:URL名称'

模板中使用:

{% url 'app01:detail' pk=12 pp=99 %}

views中的函数中使用

v = reverse('app01:detail', kwargs={'pk':11})

这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

Django框架——基础之路由系统(urls.py)的更多相关文章

  1. Django框架——基础之路由系统(urls.py)11111111

    1.URL路由系统前言 URL是Web服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的URL地址,然后被响应. 在Django项目中编写路由,就是向外暴露我们接收哪些URL的请求,除 ...

  2. Django框架——基础之视图系统(View.py)

    Django框架之View.py(视图文件) 1. 视图简介 视图层是Django处理请求的核心代码层,我们大多数Python代码都集中在这一层面. 它对外接收用户请求,对内调度模型层和模版层,统合数 ...

  3. Django框架基础知识13-auth系统

    我们昨天登录admin时创建的用户信息是存放在哪里了呢? auth系统的数据表: 从表的名称我们就能看出, auth_user,auth_group,auth_permission分别存放了用户,用户 ...

  4. Django框架——基础之模板系统(template文件夹)

    ---恢复内容开始--- 1. 常用语法 需要记住两组特殊符号:{{  }}  和 {%  %}. 在运用到变量的时候使用{{  }},如果是跟逻辑相关的话就使用{%  %}. 在Django模板(t ...

  5. Django框架——基础之模型系统(ORM的介绍和字段及字段参数)

    1.ORM简介 1.1 ORM的概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM ...

  6. Django框架——基础之模型系统(ORM相关操作)

    ------------恢复内容开始------------ 1.必定会的十三条! 1.1记忆方法一:(按字母顺序记忆)   <1> all(): 查询所有结果 <2> cou ...

  7. Django框架——基础教程(总)

    1. Django简介 Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架 ...

  8. Django(二)路由系统、视图、模板

    大纲 一.内容概要: 二.上节回顾 三.Django 视图–views  1.获取用户多个数据及文件上传  2.FBV 和 CBV  3.装饰器 四.Django模板补充  - Django模板语言循 ...

  9. Django框架搭建(windows系统)

    Django框架搭建(windows系统) 一.Django简介 开放源代码的Web应用框架,由Python语言编写,一个大而全的框架. 1.web框架介绍 具体介绍Django之前,必须先介绍WEB ...

随机推荐

  1. koa 应用生成器

    通过应用 koa 脚手架生成工具 可以快速创建一个基于 koa2 的应用的骨架 1.全局安装 npm install koa-generator -g 2.创建项目 koa koa_demo 3.安装 ...

  2. ActivityLifecycleCallbacks

    public class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks, ActivityS ...

  3. 域名到IP 报错socket.gaierror: [Errno 8] nodename nor servname provided, or not known

    Python中如何通过域名,查看对应的IP? 请看如下代码: import socket hostname="www.baidu.com" ip = socket.gethostb ...

  4. LC 712. Minimum ASCII Delete Sum for Two Strings

    Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal. ...

  5. git push 本地项目推送到远程分支[z]

    大家有的时候,会在本地新建项目,这里说一下在本地项目建立本地git仓库,然后push到远程仓库的步骤 1.在本地项目的文件夹下,git仓库初始化 git init 初始化本地git仓库 2. git ...

  6. 如何删除link-local(169.255.0.0) 路由表项

    route -n 时你总能看到这样一条路由Destination Gateway Genmask Flags Metric Ref Use Iface169.254.0.0 0.0.0.0 255.2 ...

  7. docker批量删除容器、镜像(转载)

    1.删除所有容器 docker rm `docker ps -a -q` 2.删除所有镜像 docker rmi `docker images -q` 3.按条件删除镜像 没有打标签 docker r ...

  8. 1-2、kubernetes架构概述和kubernetes基础概念

    kubernetes https://draveness.me/understanding-kubernetes http://kubernetes.kansea.com/docs/ master/n ...

  9. Node、Document关系的探究

    上图来自于<JavaScript权威指南(第六版)>P375 受到上图的启发,写了如下测试代码: var head = document.getElementsByTagName(&quo ...

  10. windows下sqlplus怎么连接远程oracle

    语法:sqlplus usr/pwd@//host:port/sid [oracle@mzl ~]$ sqlplus system/51411482@//192.168.21.11:1521/orcl ...