Django路由控制
一、简单的路由配置
from django.conf.urls import url urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ] #正则表达式:一个正则表达式字符串 #views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串 #参数:可选的要传递给视图函数的默认参数(字典形式) #别名:一个可选的name参数
1、精准匹配
#由于是正则匹配,匹配成功后不再往下匹配,输入loginaaa时只能访问到login, urlpatterns = [ url(r'^admin/', admin.site.urls), url('login',views.login), url('loginaaa',views.login), ] #精准匹配(^以什么开头,$以什么结尾) 'r'可选项,一般建议加上 url(r'^login/',views.login), url(r'^loginaaa/',views.login), #严格模式 #APPEND_SLASH = True 配置文件中默认没有 APPEND_SLASH 这个参数, Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/' 可以在在settings.py中设置了 APPEND_SLASH=False
二、路由分发
1、无名分组(按位置参数传参)
1、一般模式
#publish/匹配四位数字 url(r'^login/[0-9]{4}/$', views.login), #匹配任意长度的数字 url(r'^login/\d+/$', views.login), 2、无名分组 #无名分组,与上边的唯一区别就是外边有小括号 #但是,会把括号内的内容当作位置参数传给视图函数 #如果有两个分组,后端需要两个参数接收 url(r'^login/([0-9]{4})/$', views.login), url(r'^login/([0-9]{4})/([0-9]{2})$', views.login), def login(request,year) 一个分组 def login(request,year,month) 两个分组 def publish(request,*args): #可以这样接收多个参数,不推荐这么使用
2、有名分组(按关键字参数传参)
#用法和无名分组类似,(有名分组和无名分组,不要混用) #固定写法 ?P<参数> url(r'^publish/(?P<year>[0-9]{4})/(?P<mounth>[0-9]{2})/$', views.publish), -def publish(request, mounth,year): #视图函数需要有关键字参数接收,顺序无所谓,关键得有对应的参数 def publish(request, mounth,year):
三、路由分发
#首先创建app,在app下创建urls,这些app下的路由为子路由#主路由是django项目下的urls
1、主路由
from django.conf.urls import url,include 忘记怎么导入也不要紧,上边官方注释中有 #注意!!!,不要使用$ #方式一,取别名 from app01 import urls as a1 from app02 import urls as a2 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/',include(a1)), url(r'^app02/',include(a2)) ] #方式二(推荐使用) #直接使用app名.urls,注意这里是字符串,django内部会通过反射的方式找到 #并且,不需要导入from app01 import urls urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls')) ]
子路由
#正常使用就行,注意导入自己app的views from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/',views.login), from app02 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/',views.login), ]
四、 反向解析
#先命一个名: -1 无参数:url(r'^publishadd133/$', views.publishadd,name='ddd'), #先取别名 -2 无名分组:url(r'^publishadd/([0-9]{4})/([0-9]{2})/$', views.publishadd,name='ddd'), -3 有名分组:url(r'^publishadd/(?P<year>[0-9]{4})/(?P<mounth>[0-9]{2})/$', views.publishadd,name='ddd'), #在模板层: -1 无参数:{% url 'ddd' %} #直接使用别名,需要参数的传参数 -2 无名分组的:{% url 'ddd' 2018 12 %} -3 有名分组:{% url 'ddd' 2018 12 %} 还可以 {% url 'ddd' year=2018 mounth=12 %} #在视图层: from django.shortcuts import reverse 在视图函数里: 1 无参数:url=reverse('ddd')
return redirect(url) 1 无名分组:url=reverse('ddd',args=(2018,12,)) 1 有名分组:url=reverse('ddd',args=(2018,12,)) 还可以 url=reverse('ddd',kwargs={'year':2018,'mounth':12})
五、 名称空间
我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。
创建一个app02:python manage.py startapp app02
总urls.py
from django.urls import path,re_path,include urlpatterns = [ path('app01/', include('app01.urls')), path('app02/', include('app02.urls')) ]
app01 的urls.py
from django.urls import path,re_path from app01 import views urlpatterns = [ re_path(r'index/',views.index,name='index'), ]
app02 的urls.py
from django.urls import path, re_path, include from app02 import views urlpatterns = [ re_path(r'index/', views.index,name='index'), ]
app01的视图函数
def index(request): url=reverse('index') print(url) return HttpResponse('index app01')
app02的视图函数
def index(request): url=reverse('index') print(url) return HttpResponse('index app02')
这样都找index,app01和app02找到的都是app02的index
如何处理?在路由分发的时候指定名称空间
总urls.py在路由分发时,指定名称空间
path('app01/', include(('app01.urls','app01'))), path('app02/', include(('app02.urls','app02')))
url(r'app01/',include('app01.urls',namespace='app01')), url(r'app02/',include('app02.urls',namespace='app02'))
url(r'app01/',include(('app01.urls','app01'))), url(r'app02/',include(('app02.urls','app02')))
在视图函数反向解析的时候,指定是那个名称空间下的
url=reverse('app02:index') print(url) url2=reverse('app01:index') print(url2)
在模版里:
<a href="{% url 'app02:index'%}">哈哈</a>
七 django2.0版的path
django2.0的re_path和1.0的url一样
思考情况如下:
urlpatterns = [
re_path('articles/(?P<year>[0-9]{4})/', year_archive),
re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),
re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),
re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),
]
考虑下这样的两个问题:
第一个问题,函数 year_archive
中year参数是字符串类型的,因此需要先转化为整数类型的变量值,当然year=int(year)
不会有诸如如TypeError或者ValueError的异常。那么有没有一种方法,在url中,使得这一转化步骤可以由Django自动完成?
第二个问题,三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后article_id规则改变后,需要同时修改三处代码,那么有没有一种方法,只需修改一处即可?
在Django2.0中,可以使用 path
解决以上的两个问题。
基本示例
这是一个简单的例子:
from django.urls import path
from . 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>/', views.article_detail),
# path才支持,re_path不支持
path('order/<int:year>',views.order), ]
基本规则:
- 使用尖括号(
<>
)从url中捕获值。 - 捕获值中可以包含一个转化器类型(converter type),比如使用
<int:name>
捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了/
字符。 - 无需添加前导斜杠。
以下是根据 2.0官方文档 而整理的示例分析表:(跟上面url的匹配关系)
path转化器
文档原文是Path converters,暂且翻译为转化器。
Django默认支持以下5个转化器:
- str,匹配除了路径分隔符(
/
)之外的非空字符串,这是默认的形式 - int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
注册自定义转化器
对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
regex
类属性,字符串类型
to_python(self, value)
方法,value是由类属性regex
所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。to_url(self, value)
方法,和to_python
相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
例子:
class FourDigitYearConverter:
regex = '[0-9]{4}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return '%04d' % value
使用register_converter
将其注册到URL配置中:
from django.urls import register_converter, path
from . import converters, views
register_converter(converters.FourDigitYearConverter, 'yyyy')
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<yyyy:year>/', views.year_archive),
...
]
#伪静态 #路由 url(r^book/(?p<id>\d+.html)',viws.book), +.html) #访问 :=http://127.0.0.1:8000/book/4.html