Django版本:
>>> django.VERSION
(4, 1, 0, 'final', 0)
PS:基于前几章的进度进行修改
路由简单的说就是根据用户请求的URL连接来判断对应的处理程序,并且返回处理结果
路由主要用于建立URL与Django视图之间的映射关系。路由在urls.py
文件配置,urls.py文件中每一条配置都对应了处理程序
不同版本的Django,urls.py
文件的配置也有点差异
Django1.1.X版本:
url()
:普通路径和正则路径都可以使用,需要自己手动添加正则首位限制符号,例如:from django.conf.urls import url # 用 url 需要引入 urlpatterns = [ url(r'^admin/$', admin.site.urls), url(r'^index/$', views.index), # 普通路径 url(r'^articles/([0-9]{4})/$', views.articles), # 正则路径 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
path()
:代替1.1版本的url()方法,不需要手动添加正则首位限制符号,底层已经添加
re_path()
:用于正则路径,需要自己手动添加正则首位限制符号from django.urls import re_path # 用re_path 需要引入 urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), # 普通路径 re_path(r'^articles/([0-9]{4})/$', views.articles), # 正则路径 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
request
参数,其他形参的数量要与urls中的分组数量一致,否则会报错- 修改urls.py文件
#-*- coding: utf-8 -*-
from django.urls import re_path
from . import views
urlpatterns = [
re_path("^test/([0-9]{4})/$",views.test), #匹配以test开头,/结尾,例如/test/1234/
]
- 修改views.py文件
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test(request,year):
print(year)
return HttpResponse("Test")
127.0.0.1:8000/test/2022
,观察终端输出,最终print输出的是2022
,这是因为方法的一个形参,代表路径中一个分组的内容,按顺序进行匹配,year
参数匹配的是第二个分组([0-9]{4})
,所以最终输出2022
(?P<组名>正则表达式) #大写的P
request
参数,其他形参的数量要与urls中的分组数量一致,并且views中的形参名称要与urls中的组名相对应- 修改urls.py文件
#-*- coding: utf-8 -*-
from django.urls import re_path
from . import views
urlpatterns = [
re_path("^test/(?P[0-9]{4})/(?P[0-9]{2})/$" ,views.test),
]
#分别指定year参数与month参数
- 修改views.py文件
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test(request,year,month):
print(year,month)
return HttpResponse("Test")
127.0.0.1:8000/test/2022/08
,查看终端输出
注意:无名分组和有名分组不能混用!!
- 在每个app目录中都创建一个
urls.py
文件- 在项目名称目录下的
urls.py
文件中,统一将路径分发给各app目录
test1
和test2
urls.py
和views.py
文件helloworld
主app目录下的urls.py
文件#-*- coding: utf-8 -*-
from django.urls import re_path,path,include
from . import views
urlpatterns = [
path('Year/',include("test1.urls")), #分发给两个app目录下的urls.py文件
path('Month/',include("test2.urls")),
]
usrl.py
文件- test1/urls.py
#-*- coding: utf-8 -*-
from django.urls import re_path
from . import views
urlpatterns = [
re_path('test1/(?P[0-9]{4})/$' ,views.test1),
]
- test2/urls.py
#-*- coding: utf-8 -*-
from django.urls import re_path
from . import views
urlpatterns = [
re_path('test2/(?P[0-9]{2})/$' ,views.test2),
]
views.py
文件- test1/views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test1(request,year):
print(year)
return HttpResponse("Test1")
- test2/views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test2(request,month):
print(month)
return HttpResponse("Test2")
127.0.0.1:8000/Year/test1/2022/
,观察终端输出注意:访问的资源路径是主app的urls路径加分发的app的urls路径,所以最终是/Year/test1/2022
127.0.0.1:8000/Month/test2/08/
,观察终端输出在视图层和模板层动态反向解析出更改后的url
,这样就免去了修改的操作“别名”
,语法为:name="别名"
,实例:- 修改urls.py文件
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index/',views.index),
path('login/',views.login,name="login"), #别名login
]
- 在views.py文件中,从urls引入reverse,利用reverse("别名")进行反向解析
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
if request.method == "GET":
return HttpResponse("请使用POST")
else:
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == 'zhangsan' and pwd == '123456':
return HttpResponse("登录成功!!")
else:
return redirect(reverse('login')) #反向解析
def login(request):
return HttpResponse('请传入 username 和 pwd 参数')
127.0.0.1:8000/index/
postman
不加参数进行访问127.0.0.1:8000/index/
,查看终端输出,可以看到302跳转,并且跳转是通过GET方式访问的login资源postman
访问,添加username
和pwd
参数re_path
方法,同样通过name='别名'
配置路径别名,实例:- 修改urls.py文件
#-*- coding: utf-8 -*-
from django.urls import path,re_path
from . import views
urlpatterns = [
path('index/',views.index),
re_path('^login/([0-9]{4})/$',views.login,name="login"),
]
- 修改views.py
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
if request.method == "GET":
return HttpResponse("请使用POST")
else:
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == 'zhangsan' and pwd == '123456':
return HttpResponse("登录成功!!")
else:
return redirect(reverse('login',args=('2022',)))
@csrf_exempt
def login(request,year): #添加一个参数
print(year)
return HttpResponse('Test')
postman
访问127.0.0.1:8000/index
,观察终端
- 修改urls.py文件
#-*- coding: utf-8 -*-
from django.urls import path,re_path
from . import views
urlpatterns = [
path('index/',views.index),
re_path('^login/(?P[0-9]{4})/(?P[0-9]{2})/$' ,views.login,name="login"),
]
- 修改views.py文件
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
if request.method == "GET":
return HttpResponse("请使用POST")
else:
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == 'zhangsan' and pwd == '123456':
return HttpResponse("登录成功!!")
else:
return redirect(reverse('login',kwargs={"year":"2022","month":"09"}))
@csrf_exempt
def login(request,year,month):
print(year + month)
return HttpResponse('Test')
postman
访问127.0.0.1:8000/index
,观察终端在模板文件(html文件)中使用反向解析,利用{% url '别名' %}
urls.py文件
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index/',views.index),
path('login/',views.login,name="login"), #别名login
]
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
def index(request): #index资源返回html页面,页面使用post方法反向解析到login资源
return render(request,"test.html")
@csrf_exempt #因为html使用post方法,所以需要使用装饰器将此函数可以接受post方式
def login(request):
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == "zhangsan" and pwd == "123456":
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>用户登录</h3>
<form action="{% url 'login' %}" method="post">
{% csrf_token %} #使用post方式,需要添加
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="pwd"></p>
<input type="submit">
</form>
</body>
</html>
127.0.0.1:8000/index/
,先输出正确的username
和pwd
,查看终端输出,然后输出错误的参数
使用正则路径时,模板中利用{% url "别名" 符合正则匹配的参数 %}
来实现反向解析
urls.py文件
#-*- coding: utf-8 -*-
from django.urls import path,re_path
from . import views
urlpatterns = [
path('index/',views.index),
re_path('^login/([0-9]{4})/$',views.login,name="login"), #别名login
]
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
def index(request):
return render(request,"test.html")
@csrf_exempt
def login(request,year): #增加参数year
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == "zhangsan" and pwd == "123456":
return HttpResponse("登录成功,当前年份:" + year)
else:
return HttpResponse("登录失败,当前年份:" + year)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>用户登录</h3>
<form action="{% url 'login' '2022' %}" method="post"> #无名分组,添加参数
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="pwd"></p>
<input type="submit">
</form>
</body>
</html>
127.0.0.1:8000/index/
,使用正确的username
和pwd
,查看终端输出,然后使用错误的参数进行访问
使用正则路径时,模板中利用{% url "别名" 分组名=符合正则匹配的参数 %}
来实现反向解析,多个分组,使用空格
分割
urls.py文件
#-*- coding: utf-8 -*-
from operator import indexOf
from django.urls import path,re_path
from . import views
urlpatterns = [
path('index/',views.index),
re_path('^login/(?P[0-9]{4})/(?P[0-9]{2})/$' ,views.login,name="login"), #别名login
]
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import redirect,render
from django.views.decorators.csrf import csrf_exempt
def index(request):
return render(request,"test.html")
@csrf_exempt
def login(request,year,month): #添加新参数
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == "zhangsan" and pwd == "123456":
return HttpResponse("登录成功,当前年份:" + year + "月份" + month)
else:
return HttpResponse("登录失败,当前年份:" + year + "月份" + month)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>用户登录</h3>
<form action="{% url 'login' year='2022' month='09' %}" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="pwd"></p>
<input type="submit">
</form>
</body>
</html>
127.0.0.1:8000/index/
,使用正确的username
和pwd
,查看终端输出,然后使用错误的参数进行访问
命名空间(namespace),表示标识符的可见范围,一个标识符可以在多个命名空间定义,不同命名空间的标识符含义不会相干
一个新的命名空间可以定义任意标识符,并且不会与其他命名空间的相同标识符发生冲突
使用原因:
路由别名没有作用域,而Django在反向解析URL时会进行全局搜索,搜索到的第一个路由别名,会直接返回,当在不同app目录下定义相同的路由别名时,可能会导致反向解析错误,而命名空间就可以解决这个问题
helloworld
同等目录下创建test1
和test2
,并且分别在两个目录下创建urls.py
和views.py
urls.py
和views.py
- test1的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index1/',views.test1),
]
- test1的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test1(request):
return HttpResponse("Test1")
- test2的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index2/',views.test2),
]
- test2的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
def test2(request):
return HttpResponse("Test2")
helloworld/urls.py
,这个是主app#-*- coding: utf-8 -*-
from django.urls import path,include #导入include
#from . import views
urlpatterns = [
path('test1/',include("test1.urls")), #导入两个app
path('test2/',include("test2.urls")),
]
include参数直接传一个元组,元组的第一个参数是指定APP的
urls
,第二个参数是指定命名空间
127.0.0.1:8000/test1/index1
和127.0.0.1:8000/test2/index2
index
- test1的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index1/',views.test1,name='index'),
]
- test2的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
urlpatterns = [
path('index2/',views.test2,name='index'),
]
index
- test1的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.urls import reverse
def test1(request):
return HttpResponse(reverse('index')) #输出reverse('index')会返回反向解析的资源路径
- test2的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.urls import reverse
def test2(request):
return HttpResponse(reverse('index'))
test2/index2
也就是test2的资源路径,这样肯定是不符合需求的,现在来加上命名空间造成这样的结果,是因为别名是没有作用域的,所以在django反向解析时,会在项目全局顺序搜索,当查找到第一个时,就会直接返回
- test1的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
app_name = 'test1' #设置命名空间名称
urlpatterns = [
path('index1/',views.test1,name='index'),
]
- test2的urls.py
#-*- coding: utf-8 -*-
from django.urls import path
from . import views
app_name = 'test2'
urlpatterns = [
path('index2/',views.test2,name='index'),
]
helloworld/urls.py
#-*- coding: utf-8 -*-
from django.urls import path,include
#from . import views
urlpatterns = [
path('test1/',include("test1.urls",namespace='test1')), #指定命名空间
path('test2/',include("test2.urls",namespace='test2')),
]
views.py
- test1的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.urls import reverse
def test1(request):
return HttpResponse(reverse('test1:index')) #test1表示命名空间,index表示别名
- test2的views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.urls import reverse
def test2(request):
return HttpResponse(reverse('test2:index'))
成功达到的目的!!!
模板使用命名空间和使用reverse相似,同样也是在指定别名时,前面添加命名空间名称,例如:
{% url '命名空间名称:别名' %}