django不同版本的路由配置
django 2之前,配置urlpatterns使用的是url方法
django 2之后,配置urlpatterns使用的是path方法
path与url的区别:
url()的第一个参数(即需要匹配的路径字符串),能够使用正则表达式
path()的第一个参数,不能够使用正则表达式
但是,django 2之后提供了一种支持正则表达式的路径匹配方法:re_path
re_path的使用方法和url一样
路由配置
基本格式:
url(正则表达式,views视图,参数,别名 )
re_path(正则表达式,views视图,参数,别名 )
path(路径字符串,views视图,参数,别名 )
使用正则表达式进行路径匹配时,需要注意:
1、所写的正则表达式必须能够准确匹配到相应的路径
2、尤其要注意^和$的使用
如果需要匹配到路径index,即127.0.0.1:8000/index
正则表达式应该为:^index$
而不能是:^index/$,这个表达式匹配到的路径是index/
其次如果不写^和$也容易出错
这样的话,只要路径中包含index子串就会被匹配到,导致真正处理该路径的视图函数无法被调用到
这是因为路由匹配的顺序是从urlpatterns列表的第一个元素到最后一个元素,只要匹配过程中能够匹配成功,就不再继续往后匹配了,那么这个正则表达式就会导致上述问题的发送。
分组匹配和分组命名匹配(使用正则匹配)
静态路由:只能匹配到指定url
动态路由:能够匹配到多个符合正则要求的url
分组匹配:
形如:url(r'^index/([0-9]{4})/$', views.index)
将分组得到的值以位置参数的形式传给对应的视图函数,该视图函数需要提前定义好接受该参数的形参(否则会报错)
分组命名匹配:
形如:re_path(r'^index/(?P<num>[0-9]{4})/$'
将分组得到的值以关键字参数的形式传给对应的视图函数,其中键名就是num,键值就是匹配到的值。同样需要视图函数提前定义好接受该参数的形参
注意:
1、分组匹配和分组命名匹配不能同时用于匹配一个url,因为此时只有分组命名匹配有效
2、使用分组命名匹配后,url/path/re_path的第三个参数(是一个字典)的键名不能和分组命名的一样,如果一样的话,分组命名匹配到的值会被该参数字典相应的值覆盖后传给视图函数
url(正则表达式,views视图,参数,别名 )
该参数的作用就是就是以关键字参数的形式将键值传给视图函数
3、路由匹配到的分组参数都是字符串
补充:
django视图中的CBV,在配置路径时需要将CBV通过调用as_view方法转成FBV。其中as_view源码上有一段:
self.setup(request, *args, **kwargs)
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
self.request = request
self.args = args
self.kwargs = kwargs
setup的作用就是将request对象以及路由匹配过程中捕获到的位置参数或者关键字参数一同绑定给实例化的CBV对象,以便CBV内部的方法能够使用到它们。
include路由分发
当项目越做越大时,如果将所有的路由匹配都放在项目同名的目录下的urls文件中,将会造成可读性差,耦合性高。
最好的方式就是各个app管理自己的路由,此时就需要用到include来做路由分发
形如:path('app01/', include('app01.urls'))
将匹配到前缀为app01的路径,交给app01.urls来进一步匹配
此时若app01.urls中有这么一个path:
path('index/', views.index) 那么它匹配到的路径就是 app01/index/
URL的命名与反向解析
在开发过程中,有时候需要对路由匹配的路径做修改,这样就会导致前端页面上的超链接地址也要跟着修改,视图函数中相应的重定向地址也不例外。
为了简化该过程,可以使用URL命名与反向解析:
URL的命名:path('index', views.Cbv.as_view(), name='abc')
然后就可以通过abc获取到对应的路径index
反向解析:
1、模板文件中,<a href="{% url 'abc' %}"> {% url 'abc' %}</a>
通过{% url 'url对应的名称' %}就能够获取到相应的路径,即/index
往后要是将该index修改成其他路径,也无需修改模板文件中对应的超链接地址
2、视图函数中
需要先导入from django.urls import reverse
然后使用reverse("abc")就能够获取到abc对应的路径了
以上操作只是针对静态路由,对于动态路由还分为:
无名分组:
URL的命名:re_path(r'^index/([0-9]{4})$', views.Cbv.as_view(), name='abc')
反向解析:
1、模板文件中
<a href="{% url 'abc' '2020' %}"> {% url 'abc' '2020'%}</a>
需要带上相应的位置参数,否则报错
2、视图函数中
reverse("abc", args=("2020",))
也需要加上相应的位置参数
有名分组:
URL的命名:re_path(r'^index/(?P<num>[0-9]{4})$', views.Cbv.as_view(), name='abc')
反向解析:
1、模板文件中
a、<a href="{% url 'abc' '2020' %}"> {% url 'abc' '2020'%}</a>
可以用位置参数的形式,不过位置参数的顺序必须和分组名称顺序一致
b、{% url 'abc' num='2020' %}
还可以直接用关键字赋值的形式
2、视图函数中
a、reverse("abc", args=("2020",))
b、reverse("abc", kwargs={"num": "2020"})
namespace
和他人协作开发过程中,不同的app中可出现同名的路径、view函数以及URL的命名
如:
app01:path("index", views.index, name="abc")
app02:path("index", views.index, name="abc")
此时,反向解析就会出错
因为通过反向解析获取相应的路径时,django会将整个urlpatterns列表都扫描一遍,并不会因为中途匹配到某个路径后停止扫描,那么就会造成同名的url获取出来的路径是最后一个匹配到的路径,导致错误。
这点与路由匹配过程不同,路由匹配是只要匹配到就停止对urlpatterns的扫描
解决方式:
在路由分发的时候,加上namespace属性,然后在方向解析时,使用namespace标注某个url所在的有效区域
path('app01/', include('app01.urls',namespace='app01'))
反向解析
1、模板文件中
{% url 'app01:abc' %}
2、视图函数中
reverse("app01:abc")
补充:
redirect的to参数,可以直接填写url的名称(不通过reverse解析),也能够重定向到对应的路径