Django路由层
一 django请求生命流程图
二 Django如何处理一个请求
下边是一个简单的路由匹配
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls'))
]
# app01\urls.py
from django.urls import path
from app01 import views
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)
]
# app01\views.py
from django.shortcuts import render, HttpResponse
# Create your views here.
def special_case_2003(request):
return HttpResponse('special_case_2003')
def year_archive(request, year):
return HttpResponse(f'{year}')
def month_archive(request, year, month):
return HttpResponse(f'{year}-{month}')
def article_detail(request, year, month, slug):
return HttpResponse(f'{year}-{month}-{slug}')
注意:
- 要从URL中取值,使用尖括号。
- 捕获的值可以选择性的包含转换器类型。比如<int:year>来捕获整型参数。如果不包含转换器,则会匹配除了/外的任何字符。
一些请求的例子:
- http://127.0.0.1:8000/app01/articles/2003/ 会匹配URL列表中的第一项。Django会调用views.special_case_2003(request)函数。
- http://127.0.0.1:8000/app01/articles/2022/9/ 会匹配URL列表中的第三项。Django会调用函数views.month_archive(request, year=2022,month=9)。
- http://127.0.0.1:8000/app01/articles/2022/9/HelloWorld/ 会匹配URL列表中的最后一项,Django会调用函数views.article_detail(request, year=2003, month=3, slug=“HelloWorld”) 。
三 路径转换器
- str - 匹配除了’ / '之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。
- int - 匹配0或者任何正整数,返回一个int类型。
- slug - 匹配任意由ASCII字母或数字以及连字符或下划线组成的短标签。
- uuid - 匹配一个格式化的uuid。
- path - 匹配非空字段,包括路径分隔符’ / '。允许匹配完整的路径而不像str那样匹配URL的一部分。
四 使用正则表达式
如果路径和转化器语法不能很好的定义你的URL模式,你可以使用正则表达式。
在python正则表达式中,命名正则表达式组的语法是 (?Ppattern) ,其中name是组名,pattern是要匹配的模式。
这里用先前的 app01\views.py 重写一下
# app01\urls.py
from django.urls import path, re_path
from app01 import views
urlpatterns = [
# path('articles/2003/', views.special_case_2003),
re_path('^articles/2003/$', views.special_case_2003),
# path('articles/<int:year>/', views.year_archive),
re_path('^articles/(?P<year>[0-9]{4})/$', views.year_archive),
# path('articles/<int:year>/<int:month>/', views.month_archive),
re_path('^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/$', views.month_archive),
# path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
re_path('^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/(?P<slug>[\w-]+/$)', views.article_detail)
]
实现了和前面大致相同的功能,无论正则表达式进行哪种匹配每个捕获的参数都作为字符串发送到视图中。
五 使用未命名的正则表达式组
命名组语法,例如 (?P[0-9]{4}) ,你也可以使用更短的未命名组,例如 ([0-9]{4}) 。
不是特别推荐这个用法,因为它会更容易在匹配的预期含义和视图参数之间引发错误。
在任何情况下,推荐在给定的正则表达式里只使用一个样式。当混杂两种样式时,任何未命名的组都会被忽略,而且只有命名的组才会传递给视图函数。
六 URL的反向解析
6.1 Django中URL会出现在什么位置?
- 模板(HTML)
<a href=“url”> 超链接,点击跳转至该url
<form action=“url” method=“post”> form表单中提交的数据以post请求发送至url - 视图函数中
HttpResponseRedirect(‘url’) 将用户地址栏中的地址跳转到url
6.2 反向解析
从相应的 Django 视图标识以及要传递给它的参数来获取相关联的 URL 。
模板中通过URL实现地址反向解析。
示例一:
# urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('home/', views.home),
path('test_url/', views.test, name='t')
]
# views.py
def home(request):
return render(request, 'test.html')
def test(request):
return HttpResponse('test')
# test.html
<a href="{% url 't' %}" class="btn btn-info">url反向解析</a>
测试:
点击按钮:
示例二:
# urls.py中添加
path('test_url_1/<int:age>/', views.test2, name='t2')
# views.py
def test2(request, age):
return HttpResponse(f'test2 age:{age}')
<a href="{% url 't2' '100'%} " class="btn btn-info">url反向解析测试2</a>
测试:
点击测试二按钮:
视图中通过reverse函数进行解析
示例:
path('test_url_1/<int:age>/', views.test2, name='t2'),
path('test_view_func/<int:year>/', views.view_func, name='view')
def test2(request, age):
from django.urls import reverse
url = reverse('view', kwargs={'year': age})
from django.http import HttpResponseRedirect
return HttpResponseRedirect(url)
测试:
点击测试2:
注意:当路由中有不确定的匹配因素 反向解析的时候需要人为给出一个具体的值。
七 名称空间
有路由分发场景下多个应用在涉及到反向解析别名冲突的时候无法正常解析
解决方式1
名称空间
path('app01/', include(('app01.urls', 'app01'), namespace='app01'))
path('app01/', include(('app01.urls', 'app02'), namespace='app02'))
解决方式2
别名不冲突即可