Django之路由层

路由匹配

根据用户请求的 URL 链接来判断对应的处理程序,并返回处理结果,也就是 URL 与 Django 的视图建立映射关系。Django 路由在 urls.py 配置,urls.py 中的每一条配置对应相应的处理方法。

  1. from django.conf.urls import url
  2. from app01 import views
  3. urlpatterns = [
  4. url(r'^index/$', views.index), # url方法的第一个参数是一个正则表达式
  5. url(r'^$', views.home), # 用户不携带后缀直接访问的页面
  6. ]
  • django二次追加斜杠机制,首次匹配不上,那么django还会让浏览器默认加斜杠再次发送请求
  • 斜杠机制可以取消 但是不推荐 APPEND_SLASH = False

无名分组

urls.py

  1. from django.conf.urls import url
  2. from app01 import views
  3. urlpatterns = [
  4. url(r'^test/([0-9]{4})/$'),
  5. ]
  1. 路由匹配成功之后就会调用视图函数,默认情况下会自动给视图函数传递一个request位置参数,如果路由匹配中使用括号对正则表达式进行了分组,那么在调用视图函数的时候,会将括号内匹配到的内容当做位置参数传递给视图函数

views.py

  1. from django.shortcuts import render, HttpResponse, redirect
  2. def test(response, num): # 形参num可以是任意的
  3. print(num) # 括号内正则表达式匹配到的内容
  4. return HttpResponse('test')

有名分组

urls.py

  1. urlpatterns = [
  2. url(r"^test/(?P<sid>[0-9]{4})", views.test),
  3. ]

有名分组按关键字传参,与位置顺序无关, views 中的形参名称要与 urls 中的组名对应。无名有名分组不能在一起混合使用

views.py

  1. def test(response, sid): # 使用有名分组时,视图函数的形参名字必须与有名分组的名字一致
  2. print(sid) # 括号内正则表达式匹配到的内容
  3. return HttpResponse('test')

提示

有名分组和无名分组不能同时使用,但是每一种分组可以重复使用多次,同时在视图函数中必须有对应数量的形参进行值的接收。

  1. url(r'test/(\d+)/(\d+)/(\d+)',views.test)
  2. url(r'test/(?P<id1>\d+)/(?P<id2>\d+)/(?P<id3>\d+)', views.test)

反向解析

每一个视图对应路由,但是匹配的关系发生了变化,对应的访问地址也发生了变化。可以通过一种动态解析url的方法来避免,使用url提供的name属性给对应路由起别名,从而让与之对应的链接或跳转,根据别名动态解析url,这个动态解析url路径的过程就是反向解析

基本反向解析

urls.py

  1. urlpatterns = [
  2. url('^index/',views.index),
  3. url('^test/', views.test, name='test_view'),
  4. ]

index.html

  1. <a href="{% url 'test_view' %}">test_view</a>

views.py

  1. from django.shortcuts import render, HttpResponse, redirect, reverse
  2. def index(request):
  3. print(reverse('test_view')) # 后端通过反向解析拿到名字
  4. return render(response, 'index.html')
  5. def test(request):
  6. return HttpResponse('from test view')

无名分组反向解析

urls.py

  1. urlpatterns = [
  2. url(r'^index/',views.index),
  3. url(r'^test/(\d+)/', views.test, name='test_view'),
  4. ]

index.html

  1. <a href="{% url 'test_view' 123 %}">test_view</a>

views.py

  1. from django.shortcuts import render, HttpResponse, redirect, reverse
  2. def index(request):
  3. print(reverse('test_view', args=(666,)))
  4. return render(response, 'index.html')
  5. def test(response, *args, **kwargs):
  6. return HttpResponse('from test view')

有名分组反向解析

urls.py

  1. urlpatterns = [
  2. url(r'^index/',views.index),
  3. url(r'^test/(?P<id>\d+)/', views.test, name='test_view'),
  4. ]

index.html

  1. <a href="{% url 'test_view' id=123 %}">test_view</a>

views.py

  1. from django.shortcuts import render, HttpResponse, redirect, reverse
  2. def index(request):
  3. print(reverse('test_view', kwargs={'id': 666}))
  4. return render(response, 'index.html')
  5. def test(response, *args, **kwargs):
  6. return HttpResponse('from test view')

补充:无名有名反向解析中的手动传值,一般情况下这个值可以是数据的主键值、页面的页码、区域的编号等

路由分发

在每个app里,各自创建一个urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块中。

urls.py(总路由)

  1. from django.conf.urls import url, include
  2. # 注意不能以$结尾
  3. urlpatterns = [
  4. url(r'^app01/', include('app01.urls')),
  5. url(r'^app01/', include('app02.urls')),
  6. ]

app01下的urls.py文件

  1. from django.conf.urls import url
  2. from app01 import views
  3. urlpatterns = [
  4. url(r'^index/$', views.index,name='app01_index_view'),
  5. ]

app01下的view.py文件

  1. from django.shortcuts import render, HttpResponse
  2. from django.urls import reverse
  3. # Create your views here.
  4. def index(request):
  5. url = reverse('app01_index_view')
  6. return HttpResponse('app01的index页面,反向解析结果为%s' % url)

app02下的urls.py文件

  1. from django.conf.urls import url
  2. from app01 import views
  3. urlpatterns = [
  4. url(r'^index/$', views.index,name='app02_index_view'),
  5. ]

app02下的view.py文件

  1. from django.shortcuts import render, HttpResponse
  2. from django.urls import reverse
  3. # Create your views here.
  4. def index(request):
  5. url = reverse('app02_index_view')
  6. return HttpResponse('app02的index页面,反向解析结果为%s' % url)

名称空间

不同的应用使用了相同的别名name,导致反向解析会覆盖其他应用下别名的解析。解决这个问题的方法之一就是避免使用相同的别名,如果非要使用相同的别名,那就需要用到django中名称空间的概念,将别名放到不同的名称空间中,这样即便是出现重复,彼此也不会冲突。

urls.py(总路由)

  1. from django.conf.urls import url, include
  2. urlpatterns = [
  3. url(r'^app01/', include('app01.urls',namespace='app01')),
  4. url(r'^app02/', include('app02.urls',namespace='app02')),
  5. ]

app01下的views.py

  1. from django.shortcuts import render, HttpResponse
  2. from django.urls import reverse
  3. # Create your views here.
  4. def index(request):
  5. url = reverse('app01:index_view')
  6. return HttpResponse('app01的index页面,反向解析结果为%s' % url)

app02下的views.py

  1. from django.shortcuts import render, HttpResponse
  2. from django.urls import reverse
  3. # Create your views here.
  4. def index(request):
  5. url = reverse('app02:index_view')
  6. return HttpResponse('app02的index页面,反向解析结果为%s' % url)

在html也可以这样使用

  1. {% url 'app01:index_view' %}

Django版本区别

2.x3.x与中,路由匹配是path(),path()第一个参数不在支持正则,是一个准确路径,可以用来解决数据类型转换的问题和正则表达式冗余的问题。如果想使用正则 也提供了方法,导入from django.urls import path,re_pathre_path用法与1.xurl完全一致

五个内置转化器

  • str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  • int:匹配正整数,包括0
  • slug:匹配字母、数字、下划线以及横杠组成的字符串
  • uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00
  • path:匹配任何非空字符串,包含了路径分隔符(/),不能用”?”
  1. from django.urls import path, re_path
  2. from app01 import views
  3. urlpatterns = [
  4. # path('login/<int:id>', views.login),
  5. # path('login/<str:name>', views.login),
  6. path('login/<path:p>', views.login),
  7. ]