Django路由控制
1. Django中路由的作用
- Django中,url路由的作用,就是将客户端请求的URL,映射到对应的视图函数,并且调用这个视图函数
- 路由的特点是,从上到下依次匹配,只要匹配上了,就不会再往后匹配
# urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^add_publish/', views.add_publish),
]
2. 路由简单的正则匹配
urlpatterns = [
url(r'^test/$',views.test), # 表示路由路径以test开头,以test/结尾,其他都不可以
url(r'^test/\w+$', views.test), # test后连续的字母数字下划线都可以
# 表示匹配所有,要写在所有路由后,一般用于,跳转到首页或404
url(r'',views.test)
]
# settings中配置添加,False表示不自动添加斜杠,再带后缀斜杠,就不能匹配了
APPEND_SLASH=False
3. 无名分组
3.1 正则表达式分组举例
import re
res = re.search('test/([0-9]{4})/([0-9]{2})','test/2018/20')
print(res.group())
print(res.group(1))
print(res.group(2))
test/2018/20
2018
20
3.2 利用正则分组接收客户端请求的参数
# urls.py
urlpatterns = [
url(r'^test/([0-9]{4})/([0-9]{2})', views.test), # 使用分组后,就需要视图函数进行接收函数
url(r'^test/(\d+)', views.test), # 比如请求中,带有`?nid=1` 这样的参数,直接用正则拿,不用再使用`GET.get()`方式获取了
]
# 视图函数test
def test(request,year,moth): # 有几个参数,就要接收几个,不然会报错
print(year)
print(moth)
return HttpResponse('OK')
3.2 模拟伪静态网页
- 伪静态网页,目的就是,让搜索引擎收入SEO权限更高
- 模拟伪静态网页,利用网页的分组实现,对SEO的网页优化
# urls.py
url(r'^test/(\d+).html', views.test) # 客户端请求的是静态地址.html,实际映射到test视图函数
# views.py
def test(request,id):
print(id)
# print(moth)
return HttpResponse('伪静态'+id+'.html文件')
# 模本
<a href="/test/?id=2.html">伪静态</a> # 动态网页
<a href="/test/{{ book.nid }}.html">伪静态</a> # 转为伪静态网页
4. 有名分组
- 有名分组,类似于接收关键字参数,给正则匹配出来的数据进行命名
- 有名分组的书写格式:
(?P<分组的名字>)
4.1 正则表达式有名分组举例
import re
res = re.search('test/(?P<year>[0-9]{4})/(?P<moth>[0-9]{2})','test/2018/20')
print(res.group('year'))
print(res.group('moth'))
2018
20
4.2 有名分组的使用
- 路由中关键字的名字和视图中关键字的名字,要保持一致,否则报错,视图函数的参数位置可以颠倒
# urls.py
url(r'^test/(?P<year>[0-9]{4})/(?P<moth>[0-9]{2})', views.test)
# views.py
def test(request,year,moth): # 捕获的分组数据,都是str数字类型
print(year,moth)
return HttpResponse('year:%s,moth:%s' %(year,moth))
# 有名分组可以使用`**kwargs`接收,无名分组可以使用`*args`接收,但是有名分组和无名分组不能混用
def test(request,**kwargs):
print(kwargs)
return HttpResponse('%s' %kwargs)
def test(request,*args):
print(args)
return HttpResponse('ok')
4.2 设置默认值
url(r'^test/(?P<year>[0-9]{4})/', views.test)
def test(request,year,moth=19): # 在视图中指定默认值
print(year,moth)
return HttpResponse('ok')
5. 路由分发
- 路由分发的顺序:先由总路由分发给各个app,每个app在从自己的urls.py路由中,分发视图函数,或者继续分发到下层的urls.py中,但是不推荐这样
5.1 在总的路由urls.py
中导入include
模块,并添加路由
# urls.py导入include模块
from django.conf.urls import url,include
# 添加路由,方式一(推荐)
url(r'^toapp01',include('app01.urls'))
# 添加路由,方式二
from app01 import urls
url(r'^toapp01',include('urls')
5.2 在app01中创建urls.py
# app01-urls.py
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^test01',views.test01)
]
6. 反向解析
- 反向解析:给路由url路径,其个别名
- 反向解析的作用:用户的使用是根据别名访问的,因此修改路由路径不影响使用
6.1 反向解析在视图函数中的使用
# urls.py添加别名
url(r'^test/', views.test),
url(r'^index1/', views.index, name='aaa'), # name=别名,通过访问aaa,反向解析到test
# views视图函数
def test(request):
# 映射为路由url路径,即使url路径修改,aaa也能获取到修改后的url
url=reverse('aaa')
print(url)
return redirect(url) # 重定向到url,这样url重定向就写活了
# return redirect('/index/') # 这样就写死了
def index(request):
return HttpResponse('index')
6.2 反向解析在前端页面中的使用
# views.py
def test(request):
url=reverse('aaa')
print(url)
return render(request,'test.html')
# 模板html-test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--点击后跳转到index,但是这样就写死了,路由index一变化就不能访问了-->
{#<a href="/index/">页面的反向解析</a>#}
<!--href="{% url 'aaa' %}"这样就写活了-->
<a href="{% url 'aaa' %}">页面的反向解析</a>
</body>
</html>
6.3 无名分组带参数的反向解析
# urls.py
url(r'^test/', views.test),
url(r'^index/([0-9]{4})/([0-9]{2})', views.index, name='aaa'),
# views.py
def test(request):
url=reverse('aaa',args=(2016,12)) # 映射后的参数也要传过来,字符串数字也可以
print(url)
return render(request,'test.html')
def index(request,year,month):
return HttpResponse('index')
# test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="{% url 'aaa' 2016 11 %}">页面的反向解析</a> # 页面上需要传参数
</body>
</html>
6.4 有名分组带参数的反向解析
# urls.py
url(r'^test/', views.test),
url(r'^index/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})', views.index, name='aaa'),
# views.py
def test(request):
url=reverse('aaa',kwargs={'year':2012,'month':12})
# 或者url = reverse('aaa', args=(2012,12))
print(url)
return render(request,'test.html')
def index(request,year,month):
return HttpResponse('index')
# test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="{% url 'aaa' year=2016 month=11 %}">页面的反向解析</a>
<a href="{% url 'aaa' 2016 11 %}">页面的反向解析</a> # 顺序不能颠倒
</body>
</html>
7. 名称空间
# urls.py 指定名称空间namespace='app01'
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,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^test01',views.test01, name='test') # 指定了相同的别名
]
# app02下的urls.py
from django.conf.urls import url,include
from django.contrib import admin
from app02 import views
urlpatterns = [
url(r'^test02',views.test02, name='test')
]
# app01下的views.py
def test01(request):
# test可以写成app01_test便于区分
url = reverse('app01:test') # 表示在路由分发时,只去app01找
print(url)
return HttpResponse('app01_test01')
# app02下的views.py
def test02(request):
url = reverse('app02:test') # 别名指定名称空间
print(url)
return HttpResponse('app02_test02')
# 模本中的名称空间
<a href="{% url 'app01:test' %}">html中名称空间的使用</a>
8. Django1.xx版本和Django2.xx版本的区别
8.1 路由上的区别
- 1.xx的
url
和2.xx的re_path
一样,2.xx的path
不支持正则
from django.conf.urls import url,include # 1.xx版本
from django.conf.urls import re_path,path,include # 2.xx版本