文章目录
一、路由匹配
urls.py
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名)
]
参数说明:
- 正则表达式:一个正则表达式字符串
- views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 参数:可选的要传递给视图函数的默认参数(字典形式)
- 别名:一个可选的name参数
注意事项
urlpatterns
中的元素**按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续**。- 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的’r’ 是可选的但是建议加上。
补充说明
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True
Django settings.py
配置文件中默认没有 APPEND_SLASH
这个参数,但 Django 默认这个参数为 APPEND_SLASH = True
。 其作用就是自动在网址结尾加’/’
访问 http://www.example.com/blog
时,默认将网址自动转换为 http://www.example/com/blog/
。
如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog
时就会提示找不到页面
不同Django版本路由层的区别
1.x的版本
from django.urls import url
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
"""
括号内参数--第一个是一个匹配用的正则表达式,第二个是对应视图函数
当项目特别大,路由特别多的时候需要注意路由顶替的问题
"""
使用^
限制以什么开头
,使用$
限制以什么结尾
2.x及以后的版本
from django.urls import path, re_path
urlpatterns = [
path('admin/', admin.site.urls),
]
"""
括号内参数--第一个不再是正则表达式,第一个参数写什么就是什么
re_path 跟url相同
第二个是对应视图函数
"""
并且提供了5种内置转换器,会将匹配的内容,当做关键字参数
对应给视图函数中的形参入参,也可以自定义转换器
#1、五个内置转化器
- str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
- int:匹配正整数,包括0
- slug:匹配字母、数字、下划线以及横杠组成的字符串
- uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00
- path:匹配任何非空字符串,包含了路径分隔符(/),不能用"?"
#2、示例:
- path('login/<int:year>', views.login),
- path('login/<str:name>', views.login),
- path('login/<path:p>',views.article),
#3、自定义转换器
"参考:https://codeleading.com/article/13424069936/"
二、分组命名匹配
2.1 无名分组
urlpatterns = [
url(正则表达式, views视图函数,参数,别名)
]
由于第一个参数是‘正则表达式’,那么就可以给正则的条件加上()
,进行分组
urlpatterns = [
url(r'^test/(\d+)/',views.test)
]
views.py
def test(request):
return HttpResponse('test url')
会发现,多传入了一个位置>参数
views.py
def test(request, a):
return HttpResponse(f'test url,{a}')
无名分组----路由匹配时,如果对正则表达式进行分组,那么会传入除了
request
参数外,还会分组后匹配到的内容
2.2 有名分组
有名分组其实就是对正则表达式分组之后,对分组的内容起了个别名
同时传入视图函数的时候,需要特定这个别名的关键字参数来接受
urlpatterns = [
url(r'^test/(?P<user_id>\d+)/',views.test)
]
views.py
形参中必须要有 正则表达式分组起了别名的 关键字参数
def test(request, user_id):
return HttpResponse(f'test url,{user_id}')
无名分组和有名分组不能在一个url
中混用,但是可以某种类型重复使用
2.3 传递额外的参数给视图函数
URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url()
函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
例如:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')
三、命名URL和URL反向解析
3.1 命名 URL
通过name
属性来命名,注意:多个 URL 命名是不可以重复的
urlpatterns = [
url(r'^home/', views.home, name= 'home'),
]
那么,给 URL 命名的应用场景是什么?
3.2 URL反向解析–前端
在urls.py
中给某个路径的后缀起了别名之后;
在模板 (HTML文件)中 就可以直接根据{% url'别名' %}
直接拿到起别名的路径,而不是手动拼接路径!!
这样做的好处在于,如果有修改url
的时候,就不需要手动到 模板文件中 一个一个地修改了
示例:
urlpatterns = [
url(r'^home/', views.home, name= 'home_view'),
url(r'^index/', views.index, name= 'index_view'),
]
views.py
from django.shortcuts import render, HttpResponse, redirect
def home(request):
return render(request, 'home.html')
def index(request):
return HttpResponse('from index')
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/index/">点我!要你好看</a>
<a href="{% url 'index_view' %}">点点点!!!!!</a>
</body>
</html>
此时修改urls.py
urlpatterns = [
url(r'^home/', views.home, name= 'home_view'),
url(r'^index666/', views.index, name= 'index_view'),
]
会发现反向解析的链接,能够自动解析新的路径!!
3.3 URL反向解析–后端
方式一:reverse
模块
views.py
文件
# 模块导入
from django.shortcuts import redirect, reverse
def func(request):
_url = reverse('index_view')
return redirect(f'{_url}')
urls.py
urlpatterns = [
url(r'^home/', views.home, name= 'home_view'),
url(r'^index/', views.index, name= 'index_view'),
url(r'^func/', views.func, name= 'func_view'),
]
结果:
“GET /func/ HTTP/1.1” 302 0
“GET /index/ HTTP/1.1” 200 10
方式二:
views.py
文件
# 模块导入
from django.shortcuts import redirect
def func(request):
# 可以直接写别名,也会自动跳转
return redirect('index_view')
“GET /func/ HTTP/1.1” 302 0
“GET /index/ HTTP/1.1” 200 10
3.4 无名分组反向解析
urlpatterns = [
url(r'^test/(\d+)/',views.test,name='test_view'),
]
def test(request,a):
res = reverse('index_view')
print(res)
return HttpResponse('from test')
当url
中对正则表达式进行分组之后,视图函数反向解析出/test/
之后,需要继续做后缀的匹配,如果不给一个确切的值的话,那么/test/1/
、/test/2/
、/test/666/
都符合匹配规则,所以视图函数还需要一个参数来匹配/test/
之后的参数
后端语法:
def test(request,a):
res = reverse('index_view', args=(666,))
print(res)
return HttpResponse('from test')
结果展示为:
/test/666/
如果无名分组有多个,那么在
args
括号内一次传入多个即可
前端模板语法:
{% url 'index_view' 666 %}
3.5 有名分组反向解析
urlpatterns = [
url(r'^test/(?P<user_id>\d+)/',views.test,name='test_view'),
]
后端语法:
def test(request, user_id):
res = reverse('index_view', kwargs={'user_id':666, })
print(res)
return HttpResponse('from test')
前端模板语法
{% url 'index_view' user_id=666 %}
四、路由分发
当一个项目的应用非常多时,在urls.py
文件中urlpatterns
列表中的路由会非常多,这样会导致非常不好管理路由,这时考虑将一个urls.py
文件拆分开,每一个应用单独新建一个urls,py
,通过总的路由文件对每个应用的路由文件进行统筹管理
子路由中的路由配置还是按照之前的方式,但是总路由的配置需要改变
导入模块include
#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.
#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls')), # 可以包含其他的URLconfs文件
url(r'^app02/', include('app02.urls')), # 可以包含其他的URLconfs文件
]
路由匹配时,如果匹配到/app01/
会直接到app01.urls.py
文件中去继续做路由匹配
五、名称空间
Django 项目中有两个应用–app01
与app02
,分别有其各自的urls.py
如果两个项目都有一个url(r'^index/',views.index,name='index_view')
, 即多个应用出现路由命名冲突的情况!
此时,对index_view
这个别名进行反向解析时,能够解析出是属于app01
的,还是app02
的呢?
直接说结论:当一个项目中有相同的路由命名,只会识别到最后一个起了这个名字的路由,其他的相同命名的路由,无法被反向解析出来
解决办法:在总路由进行路由分发的时候,给每个应用进行命名空间namesapce=
的起别名操作
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls',namespace='app01')),
url(r'^app02/', include('app02.urls',namespace='app02')),
]
这样在各自的视图函数进行反向解析的时候会有不同的提示
其实,该问题的解决方法还可以在给路由重命名时,加上应用的前缀app01_index_view
这样可以不使用名称空间,同样达到相同的效果