Django之路由层
路由匹配
根据用户请求的 URL 链接来判断对应的处理程序,并返回处理结果,也就是 URL 与 Django 的视图建立映射关系。Django 路由在 urls.py
配置,urls.py
中的每一条配置对应相应的处理方法。
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/$', views.index), # url方法的第一个参数是一个正则表达式
url(r'^$', views.home), # 用户不携带后缀直接访问的页面
]
- django二次追加斜杠机制,首次匹配不上,那么django还会让浏览器默认加斜杠再次发送请求
- 斜杠机制可以取消 但是不推荐
APPEND_SLASH = False
无名分组
urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^test/([0-9]{4})/$'),
]
路由匹配成功之后就会调用视图函数,默认情况下会自动给视图函数传递一个request位置参数,如果路由匹配中使用括号对正则表达式进行了分组,那么在调用视图函数的时候,会将括号内匹配到的内容当做位置参数传递给视图函数
views.py
from django.shortcuts import render, HttpResponse, redirect
def test(response, num): # 形参num可以是任意的
print(num) # 括号内正则表达式匹配到的内容
return HttpResponse('test')
有名分组
urls.py
urlpatterns = [
url(r"^test/(?P<sid>[0-9]{4})", views.test),
]
有名分组按关键字传参,与位置顺序无关, views
中的形参名称要与 urls
中的组名对应。无名有名分组不能在一起混合使用
views.py
def test(response, sid): # 使用有名分组时,视图函数的形参名字必须与有名分组的名字一致
print(sid) # 括号内正则表达式匹配到的内容
return HttpResponse('test')
提示
有名分组和无名分组不能同时使用,但是每一种分组可以重复使用多次,同时在视图函数中必须有对应数量的形参进行值的接收。
url(r'test/(\d+)/(\d+)/(\d+)',views.test)
url(r'test/(?P<id1>\d+)/(?P<id2>\d+)/(?P<id3>\d+)', views.test)
反向解析
每一个视图对应路由,但是匹配的关系发生了变化,对应的访问地址也发生了变化。可以通过一种动态解析url
的方法来避免,使用url
提供的name
属性给对应路由起别名,从而让与之对应的链接或跳转,根据别名动态解析url
,这个动态解析url
路径的过程就是反向解析
基本反向解析
urls.py
urlpatterns = [
url('^index/',views.index),
url('^test/', views.test, name='test_view'),
]
index.html
<a href="{% url 'test_view' %}">test_view</a>
views.py
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
print(reverse('test_view')) # 后端通过反向解析拿到名字
return render(response, 'index.html')
def test(request):
return HttpResponse('from test view')
无名分组反向解析
urls.py
urlpatterns = [
url(r'^index/',views.index),
url(r'^test/(\d+)/', views.test, name='test_view'),
]
index.html
<a href="{% url 'test_view' 123 %}">test_view</a>
views.py
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
print(reverse('test_view', args=(666,)))
return render(response, 'index.html')
def test(response, *args, **kwargs):
return HttpResponse('from test view')
有名分组反向解析
urls.py
urlpatterns = [
url(r'^index/',views.index),
url(r'^test/(?P<id>\d+)/', views.test, name='test_view'),
]
index.html
<a href="{% url 'test_view' id=123 %}">test_view</a>
views.py
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
print(reverse('test_view', kwargs={'id': 666}))
return render(response, 'index.html')
def test(response, *args, **kwargs):
return HttpResponse('from test view')
补充:无名有名反向解析中的手动传值,一般情况下这个值可以是数据的主键值、页面的页码、区域的编号等
路由分发
在每个app里,各自创建一个urls.py
路由模块,然后从根路由出发,将app
所属的url
请求,全部转发到相应的urls.py
模块中。
urls.py
(总路由)
from django.conf.urls import url, include
# 注意不能以$结尾
urlpatterns = [
url(r'^app01/', include('app01.urls')),
url(r'^app01/', include('app02.urls')),
]
app01
下的urls.py
文件
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/$', views.index,name='app01_index_view'),
]
app01
下的view.py
文件
from django.shortcuts import render, HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
url = reverse('app01_index_view')
return HttpResponse('app01的index页面,反向解析结果为%s' % url)
app02
下的urls.py
文件
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/$', views.index,name='app02_index_view'),
]
app02
下的view.py
文件
from django.shortcuts import render, HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
url = reverse('app02_index_view')
return HttpResponse('app02的index页面,反向解析结果为%s' % url)
名称空间
不同的应用使用了相同的别名name
,导致反向解析会覆盖其他应用下别名的解析。解决这个问题的方法之一就是避免使用相同的别名,如果非要使用相同的别名,那就需要用到django
中名称空间的概念,将别名放到不同的名称空间中,这样即便是出现重复,彼此也不会冲突。
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
下的views.py
from django.shortcuts import render, HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
url = reverse('app01:index_view')
return HttpResponse('app01的index页面,反向解析结果为%s' % url)
app02
下的views.py
from django.shortcuts import render, HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
url = reverse('app02:index_view')
return HttpResponse('app02的index页面,反向解析结果为%s' % url)
在html也可以这样使用
{% url 'app01:index_view' %}
Django版本区别
在2.x
、3.x
与中,路由匹配是path()
,path()
第一个参数不在支持正则,是一个准确路径,可以用来解决数据类型转换的问题和正则表达式冗余的问题。如果想使用正则 也提供了方法,导入from django.urls import path,re_path
,re_path
用法与1.x
的url
完全一致
五个内置转化器
str
:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式int
:匹配正整数,包括0slug
:匹配字母、数字、下划线以及横杠组成的字符串uuid
:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00path
:匹配任何非空字符串,包含了路径分隔符(/),不能用”?”
from django.urls import path, re_path
from app01 import views
urlpatterns = [
# path('login/<int:id>', views.login),
# path('login/<str:name>', views.login),
path('login/<path:p>', views.login),
]