django之反向解析和命名空间
背景:当我们页面中存放的请求路径与url文件中的url一致时,如果url改了是不是所有的请求路径都要跟着改?显然不现实,这里我们就要用到反向解析。
如下图所示,输入url后会跳转到登录页面,输入用户名密码后跳转到欢迎页面。
# 在公共项目中urls中的url from django.contrib import admin from django.urls import path, re_path, include from website import views urlpatterns = [ path('admin/', admin.site.urls), path('data/', views.data), path('login./', views.login), ] # 在应用中views文件中的视图函数 from django.shortcuts import render, HttpResponse def login(request):if request.method == 'GET': return render(request, 'login.html') elif request.method == 'POST': if request.POST.get('user') == 'admin' and request.POST.get('pwd') == '123456': return HttpResponse('welcome to world') else: return HttpResponse('用户名或密码错误')
# 在公共项目统一目录层建的templates层存放页面文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static/js.js"> </script> </head> <body> <h4> 登录页面 </h4>> <form action="http://127.0.0.1:8000/login/" method="post"> 用户名<input type="text" name="user"> 密码<input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
现在我需要把公共项目中的url改变,再次点击登录后报错了
urlpatterns = [ path('admin/', admin.site.urls), path('data/', views.data), path('login.html/', views.login), ]
报错如图所示:
因为我们登录时action中的路径找不到http://127.0.0.1:8000/login/路径,现在已经被改成了http://127.0.0.1:8000/login.html/,此时难道我们需要一直改这个路径吗?不存在的!
接下来到了反向解析的重点
在公共项目中的urls文件中把url加一个属性name
from django.contrib import admin from django.urls import path, re_path, include from website import views urlpatterns = [ path('admin/', admin.site.urls), path('data/', views.data), path('login.html/', views.login, name='hello') ]
在html中把action路径改为{{% url 'hello' %}}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static/js.js"> </script> </head> <body> <h4> 登录页面 </h4>> <form action="{% url 'hello' %}" method="post"> 用户名<input type="text" name="user"> 密码<input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
此时再次去访问页面就不会报错啦!
还有个反向解析办法就是导入reverse模块
在公共项目中的urls文件中
from django.contrib import admin from django.urls import path, re_path, include from website import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login, name='hello'), # 路由配置 路径--------》视图函数 re_path(r'^articles/2003/', views.special_case_2003, name='one'), re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='two'), re_path(r'^articles/(?P<y>[0-9]{4})/(?P<m>[[0-9]{2})/$', views.month),
在应用中的views文件中的视图函数
from django.shortcuts import render, HttpResponse import time from django.urls import reverse # Create your views here. def special_case_2003(request): return HttpResponse('special_case') def year_archive(request, year): return HttpResponse(year) def month(request, m, y): return HttpResponse(y+'+'+m) def login(request): print(reverse('one')) # reserve中放的是路径中的name print(reverse('two', args=(4099,))) # 当有元祖时参数必须放在args中 if request.method == 'GET': return render(request, 'login.html') elif request.method == 'POST': if request.POST.get('user') == 'admin' and request.POST.get('pwd') == '123456': return HttpResponse('welcome to world') else: return HttpResponse('用户名或密码错误')
输入ur:http://127.0.0.1:8000/login/后,查看reserve中的路径为下图所示
这样就把反向解析的路径获取到了 !!!
此时有个问题就来了,如果在两个应用中的url相同且对应的name也相同,那会获取到哪个路径呢?经测试得出会获取到第二个,因为第一个被第二个覆盖了。那怎么解决呢?
如下图所示
# 公共项目中的url from django.contrib import admin from django.urls import path, re_path, include from website import views urlpatterns = [ path('admin/', admin.site.urls), path('data/', views.data), path('login/', views.login, name='hello'), # 路由配置 路径--------》视图函数 # 分发 re_path(r'website/', include(('website.urls', 'website'))), re_path(r'website1/', include(('website1.urls', 'website1')))
# 在第一个项目中的url文件 from django.urls import path, re_path from website import views urlpatterns = [ # 路由配置 路径--------》视图函数 re_path('index', views.index, name='index') ] # 在第一个项目中的views文件 from django.shortcuts import render, HttpResponse from django.urls import reverse def index(request): return HttpResponse(reverse('website:index')) 这里返回第一个项目的index
# 在第二个项目中的url文件 from django.urls import path, re_path from website1 import views urlpatterns = [ # 路由配置 路径--------》视图函数 re_path('index', views.index, name='index') ] # 在第二个项目中的views文件 from django.shortcuts import render, HttpResponse from django.urls import reverse def index(request): return HttpResponse(reverse('website1:index')) # 这里返回第二个项目的index
在django2.0版本中又出现了path的用法,可以简便的使用有名分组
# 公共项目中的urls from django.contrib import admin from django.urls import path, re_path, include from pro import views urlpatterns = [ # 路由分发 re_path(r'pro/', include('pro.urls')), ]
# pro中的urls文件 from pro import views urlpatterns = [ # path('test/<int:year>', views.timer) # 参数为int型 # path('test/<slug:year>', views.timer) # 参数为字母,数字以及横杠,下划线组成的字符串 # path('test/<str:year>', views.timer) # 匹配除了/之外的非空字符串 # path('test/<uuid:year>', views.timer) # 匹配格式化的uuid # path('test/<path:year>', views.timer) # 匹配任意非空字符串 ]
# pro中的views文件 def timer(request, year): print(year) print(type(year)) return HttpResponse('欢迎大脸猫')
此时pro中的url中的写法就是简单的有名分组,<>中间是规定的参数类型及参数
以上介绍了5种转换器方法,显而易见在项目中肯定是不够用的,我们也可以自定义转换器
首先在需要的App项目中,建一个自定义转换器的类
# 此文件为pro.urlconvert 自己pro中新建 class YearConvert: regex = "[0-9]{4}" # 这个regex参数必须这样写 def to_python(self, value): # 处理返回的参数 return int(value) def to_url(self, value): return '%04d' % value
接下来去项目中注册
from django.contrib import admin from django.urls import path, re_path, include, register_converter # 这个需要导入 from pro.urlconvert import YearConvert from pro import views register_converter(YearConvert, 'yy') # 注册刚才新建的转换器类 urlpatterns = [ path('admin/', admin.site.urls), path('pro/<yy:year>', views.year_func) 此时的yy就是转换器的名称 ]
最后一步写个对应的year_func,查看效果
# 此时在pro.views from django.http import HttpResponse # Create your views here. def year_func(request, year): print(year) print(type(year)) return HttpResponse('year....')
浏览器请求效果:
此时,我们自定义的转换器就生效啦!!!!
请尊重作者劳动成果,有需要请转载,标明出处!!!