- A+
一、说明
Django 1.11版本 URLconf官方文档
Django 2.0版本URLconf官方文档
1.1、路由系统说明
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。
你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
1.2、基本格式
1.Django 1.11基本格式
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
2.Django 2.0版本中的路由系统已经替换成下面的写法
其实2.0版本除了将url关键字改为path之外其他的变动并不大.
from django.urls import path
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
参数说明:
-
正则表达式:一个正则表达式字符串
-
views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
-
参数:可选的要传递给视图函数的默认参数(字典形式)
-
别名:一个可选的name参数
二、URL中的正则表达式详解
2.1、基本配置
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003), #^articles/2003/$:表示以articles/开头并且以2013/结尾(两级(/a/b)固定的URL)
url(r'^articles/([0-9]{4})/$', views.year_archive), #^articles/([0-9]{4})/$:表示以^articles/开头,后面是0-9之间的任意四个数字组成的url结尾(两级/a/0-9/可变的url)
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #^articles/([0-9]{4})/([0-9]{2})/$:表示以^articles/开头,中间为0-9之间任意数组成的四个数字,最后是0-9之间任意两个数字组成的URL结尾(三层(/a/0-9/0-9)可变的URL),这里要注意,由于URL分组了,URL对应的函数除了默认接收一个request参数外还要接收另外两个参数,
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), #^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$:表示以^articles/开头,第二位为0-9之间的四个任意数字组成,第三位为0-9之间任意两个数字组成,结尾为0-9之间的一个或多个数字组成
]
配置多个分组的URL时,在views.py文件定义函数时,URL每多一个分组函数里对应就要多一个形参来接收参数,示例如下:
1.urls.py中的url与函数对应关系配置
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #^articles/([0-9]{4})/([0-9]{2})/$:表示以^articles/开头,中间为0-9之间任意数组成的四个数字,最后是0-9之间任意两个数字组成的URL结尾(三层(/a/0-9/0-9)可变的URL),这里要注意,由于URL分组了,URL对应的函数除了默认接收一个request参数外还要接收另外两个参数,
2.views.py中的函数写法
def month_archive(request,args1,args2): #定义函数时需要有接收URL参数的形参
print(args1) #接收参数后可以操作参数
print(args2)
···
注意事项:
- urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
- 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的'r' 是可选的但是建议加上。
补充说明# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项 APPEND_SLASH=True
Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。
其效果就是:
访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/
当将参数设置为APPEND_SLASH=False时:
访问 http://www.example.com/blog 就会提示找不到页面,需要在http://www.example.com/blog/ 才可以实现访问。
2.2、分组命名匹配
上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。
在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。
在Python的正则表达式中,分组命名正则表达式组的语法是(?P
下面是以上URLconf 使用命名组的重写:
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),
]
这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。
上面的URL参数对应的views.py里的函数写法如下:
def special_case_2003(request):
print(request)
def year_archive(request,year):
print(request,year)
def month_archive(request,year,month):
print(request,year,month)
def article_detail(request,year,month,day)
print(request,year,month,day)
在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。
至于究竟应该使用哪一种,你可以根据自己的喜好来决定。
说明:
URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。
例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。
在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。
URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。
捕获的参数永远是字符串:
每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式,传递到视图函数中的参数永远是字符串类型的。
关于正则分组命名匹配和正则分组URL匹配的使用说明:
分组命名:通过给正则表达式命名的方式,函数接收的是关键字参数,实现调用
分组URL:没有给分组命令,函数接收的就是位置参数,实现调用
重点 : 两种类型的URL命名形式不可以混合使用,容易被覆盖。
2.3、试图函数中指定默认值
# urls.py中
from django.conf.urls import url
from . import views
urlpatterns = [ #两个不同url指定了一个函数
url(r'^blog/$', views.page), #默认返回Blog的第一页
url(r'^blog/page(?P<num>[0-9]+)/$', views.page), #返回Blog具体访问的页码数
]
# views.py中,可以为num指定默认值
def page(request, num="1"):
pass
三、多级路由配置(一个django项目里有多个app)
1.创建两个app
创建app01和app02
在manage.py同级目录下执行以下命令创建app:
python manage.py startapp app01
python manage.py startapp app02
2.配置
在setting.py文件里的INSTALLED_APPS标签下:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'app02.apps.App02Config', #添加app01和app02的配置
]
3.在app01和app02下创建urls.py文件并添加如下默认配置
创建文件(PyCharm):New --> Python file --> 指定文件名字为:urls
文件中添加如下默认内容:
1.app01的urls.py配置如下:
from django.conf.urls import url
from django.contrib import admin
from app01 import views #导入自己项目下的views文件
#定义URL与函数的对应关系
urlpatterns = [
url(r'book',views.book)
]
2.app02的urls.py配置如下:
from django.conf.urls import url
from django.contrib import admin
from app02 import views #导入自己项目下的views文件
#定义URL与函数的对应关系
urlpatterns = [
url(r'book',views.book)
]
试图(views.py)文件里的函数如下:
1.app01下的views.py文件的book函数内容如下:
from django.shortcuts import render,HttpResponse
def book(request):
return HttpResponse("Welcome To App01")
2.app02下的views.py文件的book函数内容如下:
from django.shortcuts import render,HttpResponse
def book(request):
return HttpResponse("Welcome To App02")
4.主urls.py文件(setting.py同级目录)里的配置如下
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include #导入include模块
from app01 import urls as app01_urls #导入app01下的urls.py文件(URL与域名对应关系文件),为了防止和其他app冲突需要定义别名
from app02 import urls as app02_urls #导入app02下的urls.py文件(URL与域名对应关系文件),为了防止和其他app冲突需要定义别名
urlpatterns = [
url(r'^app01/', include(app01_urls)), #如果是以app01开头的文件,就通过include导入app01的URL与函数的对应关系然后app01下的urls.py去处理
url(r'^app02/', include(app02_urls)), #如果是以app02开头的文件,就通过include导入app02的URL与函数的对应关系然后app01下的urls.py去处理
]
4.实现访问
通过:127.0.0.1:8000/app01/book 实现访问app01的项目
通过:127.0.0.1:8000/app02/book 实现访问app02的项目
原理说明:
用户 --> 请求:127.0.0.1:8000/app01/book --> 先到项目下的urls.py里找对应关系 --> 找到对应关系后到app下的urls.py里找对应关系 --> 最后到views.py里实现返回浏览器内容!!
四、传递额外的参数给试图函数(了解即可)
在配置URL与函数的对应关系时可以给额外传递一个或多个参数,示例如下:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在函数里就可以获取到传的参数
def year_archive(request,foo):
print(foo) #获取到这个参数后就可以操作这个参数
...
五、命名URL与反向解析
在使用Django 项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
Django提供了一种机制,就是给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。
这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL即可。
5.1、有参数与没参数URL的命令
url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home
url(r'^book/(?P<year>[0-9]{2,4})/(?P<title>[a-zA-Z]{2})/$ ,views.book ,name="book"), # 给url匹配模式起名为book(注意:这个url路径有关键字参数)
url(r'^book1/([0-9]{2,4})/([a-zA-Z]{2})/$ ,views.book ,name="book1"), # 给url匹配模式起名为book1(注意:这个url路径有位置参数)
5.2、在模板文件中调用URL命名与试图文件中调用URL命令
在模板里面可以这样引用:
<a href="{% url 'home' %}">点击跳转</a> #没有参数的url反向解析
<a href="{% url 'home' 2018 'dream' %}">点击跳转</a> #有参数的url反向解析(模板语言里就按照位置写就可以了不用指定关键字)
在views函数中可以这样引用:
from django.urls import reverse
return redirect(reverse('home')) #没有参数的url别名跳转
return redirect(reverse('book', kwargs={"year":2019,"title":"dream"})) #有关键字参数的URL别名跳转
return redirect(reverse('book', args=("2018", "dream"))) #有位置参数的URL别名跳转
5.3、示例
1.在urls.py添加URL与函数解析设置
from django.conf.urls import url
urlpatterns = [
url(r'^url_test1/', views.default_url_test,name="default_url"), #没有参数的URL与函数映射
url(r'^url_test2/([0-9]{2,4})$', views.parameter_url,name="parameter_url"), #有参数的URL与函数映射
url(r'^url_test3/(?P<path>[a-zA-Z]{2,4})$', views.keyworld_url,name="keyworld_url"), #分组命名的URL与函数映射
]
2.在views.py中写对应的函数
from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse
def default_url_test(request): #没有参数的URL对应的函数
print("默认URL的路径:",reverse('default_url')) #在views.py里通过reverse('default_url')获取要访问的路径,结果为:url_test1
print("有参数的URL地址是:",reverse("parameter_url",args=("23",))) #有参数的URL映射通过传位置参数的形式获取要访问的路径,结果为:url_test2/23
print("关键字参数URL地址是:",reverse("keyworld_url",kwargs=({'path':'abc'}))) #分组命名的URL映射通过传关键字参数的形式获取要访问的路径,结果为:url_test3/abc
return render(request,"url_test/default_url.html")
def parameter_url(request,args1): #有位置参数的URL对应的函数
return render(request,"url_test/parameter_url.html")
def keyworld_url(request,path): #有关键字参数的URL对应的函数
return render(request,"url_test/keyworld_url.html")
3.对应的HTML文件内容如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>URL测试</title>
</head>
<body>
<h1>无参数的URL命名测试文件</h1>
<p><a href="{% url 'parameter_url' '23' %}">跳转有参数</a></p> <!-- html中通过:{% url 'parameter_url' '23' %}获取要访问的路径,前面是URl的命名,后面是参数 -->
<p><a href="{% url 'keyworld_url' 'abc' %}">跳转关键字参数</a></p>
{#<p><a href="{% url 'default_url' %}">跳转无参数</a></p>#}
</body>
</html>