Django 和其他 Web 框架的 Http 处理的流程大致相同,web服务器软件或者模块(wsgiref)会把http 发送的请求封装成了一个 Request 对象, Django 处理一个 Request 的过程首先是通过中间件,然后再通过默认的 URL 方式进行的. 我们可以在中间件(middleware)这个地方把所有 Request 拦截住,用我们自己的方式完成处理以后直接返回 Response。
1.当发起请求时,首先会根据项目目录下的根路由URLconf(urls.py)下查找路由规则urlpatterns。
2.urlpatterns变量定义为列表,元素是django. urls.path()实例 或django.urls.re_path()实例,这两种对象定义了url与视图的对应关系。
3.django会按照顺序匹配每个url模式,并匹配到第一个模式后停止匹配,且django 将导入并调用对应的视图。
4.如果没有匹配的模式,或在过程中引发了异常,django将调用错误视图。
根路由:主路由,项目目录下的urls.py,会包含其他的子路由。
子路由:各应用模块下的urls.py。
path()返回的对象就是一条路由规则,其可接收的参数:
path(route,view,kwargs=None,name=None)
# route: str格式,路由规则
# view: 视图
# kwargs: 需要传递的参数
# name: 路由的名字
继续以上篇为例:
在应用模块projects目录下的views.py文件中编写如下代码:
from django.http import HttpResponse
def index(request):
return HttpResponse('首页')
def pro(request):
return HttpResponse('项目')
创建子路由,在应用projects目录下创建urls.py文件
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro/', views.pro)
]
在项目demo1目录urls.py中添加如下路由:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', include('project.urls')),
path('', include('project.urls'))
]
当捕获url中的参数时需使用<>来定义变量名,如下:
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro)
]
视图中则需要接收这捕获到的值作为形参:
from django.http import HttpResponse
def index(request):
return HttpResponse('首页')
def pro(request,pid):
return HttpResponse(f'项目id为{pid}')
路径转换器
如果需要声明url中需捕获的参数类型,可以通过路径转换器来设置:
Django内置下面的路径转换器:
str:默认的,匹配除路径分隔符 " / " 以外的任何非空字符串
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro) #默认为str
]
int:匹配0和正整数,返回一个int类型
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro)
]
slug:匹配任何ASCII字母以及连接符和下划线,比如a_b-c
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro)
]
uuid:匹配格式化的uuid。
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro)
]
path:匹配任何非空字符串,可以包含路径分隔符 " / ",允许匹配完成的url路径。
from django.urls import path
from projects import views
urlpatterns = [
path('', views.index),
path('pro//' , views.pro)
]
re_path()
返回一个对象,表示一条正则匹配规则的url匹配模式,和path的不同为route部分包含了正则表达式。
path(route,view,kwargs=None,name=None)
当进行匹配,从正则表达式中捕获的组会被传递到视图中。如果组是命名的,则作为命名的参数,否则作为位置参数,值以字符串的形式传递,不做任何的类型转换。
有命名的分组(?P< name>pattern),name是组的名称,pattern是正则表达式.
from django.urls import path,re_path
from . import views
urlpatterns = [
path('', views.index),
re_path(r'^pro/(?P\d{4})/(?P[1-9]|1[0-2])/$' , views.pro)
]
from django.http import HttpResponse
def pro(request, year, month):
return HttpResponse(f"出生年月为:{year}-{month}")
动态获取对应视图的url。
django.shortcuts.reverse函数,接收url的名字,然后反向解析出对应的绝对路径。
from django.urls import path, re_path
from . import views
urlpatterns = [
path('', views.index),
path('detail//' , views.detail, name='detail'),
path('pro_list/', views.pro_list, name='prolist'),
re_path(r'^pro/(?P\d{4})/(?P[1-9]|1[0-2])/$' , views.pro)
]
from django.http import HttpResponse
from django.shortcuts import reverse
def detail(request, pid):
return HttpResponse('项目id为{}'.format(pid))
def pro_list(request):
print(reverse('detail', args=(2,)))
html = '''
项目1
'''.format(reverse('detail', args=(2,)))
return HttpResponse(html)
当一个项目下有多个应用时,难免会给url定义相同的名字,而如果不区分name的话,则获取不到正确的绝对路径,如下:
应用project下的urls.py
from django.urls import path
from project import views
urlpatterns = [
path('project/', views.index, name='index')
]
view代码:
from django.http import HttpResponse
from django.shortcuts import reverse
def index(request):
return HttpResponse('应用1首页{}'.format(reverse('index')))
应用project1下的urls.py
from django.urls import path
from project1 import views
urlpatterns = [
path('project1/', views.index, name='index')
]
view代码:
from django.http import HttpResponse
from django.shortcuts import reverse
def index(request):
return HttpResponse('应用2首页{}'.format(reverse('index')))
此时两个不通的项目通过url名字获取到的路由地址都为:
而通过app_name可以来区分不通应用中相同名字的路由,只需在子路由中添加变量app_name来声明,在reverse中来指定路由名字,如下:
应用project下的urls.py
from django.urls import path
from project import views
app_name = 'project'
urlpatterns = [
path('project/', views.index, name='index')
]
view代码:
from django.http import HttpResponse
from django.shortcuts import reverse
def index(request):
return HttpResponse('应用1首页{}'.format(reverse('project:index')))
应用project1下的urls.py
from django.urls import path
from project1 import views
app_name = 'project1'
urlpatterns = [
path('project1/', views.index, name='index')
]
view代码:
from django.http import HttpResponse
from django.shortcuts import reverse
def index(request):
return HttpResponse('应用2首页{}'.format(reverse('project1:index')))