Django之路由系统
路由系统
2017年12月2号,Django2.0发布,路由系统添加了path函数,与url共存。
说明:
第一,目前 路由(url)到视图(View)的流程可以概括为四个步骤:
- url匹配
- 正则捕获
- 变量类型转化
- 视图调用
Django2.0 和之前相比多了 变量类型转化 这一步骤。
第二,新的path语法可以解决一下以下几个场景:
- 类型自动转化
- 公用正则表达式
一、url(2.0依然支持url)
1、单一路由对应
url(r'^index$', views.index),
2、基于正则的路由
url(r'^index1/(\w*)/(\d*)$',views.index1), # 可通过*args获取tupple数据,也可通过制定名称参数 url(r'^index2/(?P<name>\w*)/(?P<id>\d*)$', views.index2), # 通过**kwargs获取字典数据
def index1(request,*args,**kwargs): if request.method == "GET": print(request) # request: < WSGIRequest: GET '/index1/abc/123' > print(args) # args: ('abc', '123') print(kwargs) # kwargs: {} return render(request,"index.html") def index2(request,*args,**kwargs): if request.method == "GET": print(request) # request: <WSGIRequest: GET '/index2/abc/123'> print(args) # args: () print(kwargs) # kwargs: {'name': 'abc', 'id': '123'} return render(request,"index.html")
3、添加额外的参数
url(r'^index3/(?P<name>\w*)/(?P<id>\d*)', views.index3,{'age':18}), # 仅针对views里**kwargs
def index3(request,*args,**kwargs): if request.method == "GET": print(request) # request: <WSGIRequest: GET '/index3/abc/123'> print(args) # args: () print(kwargs) # kwargs: {'name': 'abc', 'id': '123', 'age': 18} return render(request,"index.html")
4、为路由映射设置名称
url(r'^index4/(\w*)/(\d*)$', views.index4,name="h1"), # 数据匹配的个数与reverse和HTML里的参数个数一致
设置名称之后,可以在不同的地方调用,如:
- 模板中使用生成URL {% url 'h2' 2012 %}
- 函数中使用生成URL reverse('h2', args=(2012,)) 路径:django.urls.reverse
- Model中使用获取URL 自定义get_absolute_url() 方法
用法一 <h2>{% url 'h1' "abcdefghigjklmn" 2012 %}</h2> # /index4/abcdefghigjklmn/2012 用法二 r = reverse('h1', args=("abcdefg",2012,)) # /index4/abcdefg/2012 用法三 class NewType(models.Model): caption = models.CharField(max_length=16) def get_absolute_url(self): """ 为每个对象生成一个URL 应用:在对象列表中生成查看详细的URL,使用此方法即可!!! :return: """ # return '/%s/%s' % (self._meta.db_table, self.id) # 或 from django.urls import reverse return reverse('NewType.Detail', kwargs={'nid': self.id})
namespace
reverse("{0}:{1}".format(namespace,urlname))
示例
"""first_review URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path,re_path,include urlpatterns = [ re_path("testurls/",include("testurls.urls")), re_path("testurls_fornamespace/",include("testurls.urls",namespace="forurls")), ]
"""first_review URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path,re_path,include from testurls import views app_name = "testurls" # 使用了namespace,则必须定义app_name urlpatterns = [ re_path("index.html/$",views.Index.as_view(),name="index"), re_path("index.html/(?P<page>\d+)/$",views.Index.as_view(),name="index_with_kwargs"), re_path("index/(\d+).html$",views.Index.as_view(),name="index_with_args"), re_path("index2.html/$",views.Index2.as_view(),name="index2") ]
from django.shortcuts import render from django.views import View from django.urls import reverse class Index(View): def get(self,request,*args,**kwargs): # 访问/testurls/index.html/ this_url = reverse("index",) # 若有app_name = "testurls",则为testurls:index如下,已实验 print(this_url) # /testurls/index.html/ # this_url = reverse("testurls:index", ) # print(this_url) # # /testurls/index.html/ # 访问/testurls/index.html/22/ # this_url = reverse("index_with_kwargs",kwargs=kwargs) # print(this_url) # /testurls/index.html/22/ # 访问 /testurls/index/33.html # this_url = reverse("index_with_args",args=args) # print(this_url) # /testurls/index/33.html context = {"args":args} return render(request,"index2.html",context)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>{% url 'index' %}</div> <div>{% url 'index_with_kwargs' 213 %}</div> <div>{% url 'index_with_args' args.0 %}</div> </body> </html>
namespace也验证成功
5、根据app对路由规则进行分类
urls.py url(r'^index/',include('web.urls')), web/urls.py url(r'^(?P<name>\w*)/(?P<id>\d*)$',views.index) # 。。。/index/abc/123
6、命名空间
project.urls.py
from django.conf.urls import url,include urlpatterns = [ url(r'^a/', include('app01.urls', namespace='author-polls')), url(r'^b/', include('app01.urls', namespace='publisher-polls')), ]
app01.urls.py
app01.urls.py from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^(?P<pk>\d+)/$', views.detail, name='detail') ]
app01.views.py
app01.views.py def detail(request, pk): print(request.resolver_match) v = reverse('app01:detail', kwargs={'pk':11}) # ResolverMatch(func=app01.views.detail, args=(), kwargs={'pk': '123'}, url_name=detail, app_names=['app01'], namespaces=['author-polls']) print(v) return HttpResponse(pk)
以上定义带命名空间的url之后,使用name生成URL时候,应该如下:
- v = reverse('app01:detail', kwargs={'pk':11})
- {% url 'app01:detail' pk=12 pp=99 %}
二、path,re_path(版本2.0及之后)
1、re_path
from django.urls import path,re_path,include
其中,re_path具有上述url的6个功能且用法一样,只需把url替换为re_path即可。
2、path
转换器Path converters
- 默认converters
- 自定义converters
(1)Django默认支持以下5个转化器:
- str,匹配除了路径分隔符(
/
)之外的非空字符串,这是默认的形式 - int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符
################# urls.py ################# from django.urls import path urlpatterns = [ path(r"index1/<str:name>/<int:num>",views.index1), # result为一个str,一个数字 path(r"index2/<int:num1>/<int:num2>",views.index2), # 若url中num1/num2为字符串,则无法匹配此条目 ] ################# views.py ################# 访问http://127.0.0.1:8000/index1/456/123 def index1(request,*args,**kwargs): if request.method == "GET": print(request.path_info) print(request) # request: < WSGIRequest: GET '/index1/456/123' > print(args) # args: ('abc', '123') print(kwargs) #kwargs: {'name': '456', 'num': 123},一个是str,一个是int return render(request,"index.html")
(2)自定义转换器
注册自定义转化器 对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点: regex 类属性,字符串类型 to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。 to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。 ############# project/converters.py ############ class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value ############# project/urls.py ############ from django.urls import register_converter, path from . import converters, views register_converter(converters.FourDigitYearConverter, 'yyyy') urlpatterns = [ path(r"index1/<name>/<yyyy:year>",views.index1), # 根据yyyy匹配四个数字,result类型为int,kwargs: {'name': 'abc', 'year': 1231} ... ]
参考:
http://www.cnblogs.com/wupeiqi/articles/5237704.html
https://kinegratii.github.io/2017/09/25/django2-url-path/