02-URLConf调度器
1、工作原理
django通过urlconf来映射视图函数,只区分路径,不区分http方法
- Django确定要使用的根URLconf模块,一般是在settings中的ROOT_URLCONF设置的值。
- Django加载该URLconf模块并查找变量 urlpatterns,它是一个列表django.urls.path() 和 / 或django.urls.re_path()实例。根据列表的实例查找相关的路劲。
- Django按顺序遍历每个URL模式,并停在与请求的URL匹配的第一个URL模式,后面相同的模式不会再进行匹配。
- 如果某个URL模式匹配成功,Django就会导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的视图方法)。
2、简单示例:
from django.urls import path from . import views urlpatterns = [ path('blog/2003/', views.special_2003), path('blog/<int:year>/', views.year_archive), path('blog/<int:year>/<int:month>/', views.month_archive), path('blog/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
在上述路由中,有几点需要注意:
(1)从URL中捕获,使用尖括号。
(2)捕获的值可以包含转换器,如/<int:year>/,前面的int表示只能是整数参数,year是参数的名称,用于视图函数的参数传递
(3)path的路径前不需要再添加“/”,
(4)示例说明
blog/2003/匹配的是path('blog/2003/', views.special_2003),而blog/2005/匹配的是path('blog/<int:year>/', views.year_archive),
3、格式转换器
在上面的示例中,我们已经看到了int这个格式转换器的用法,格式转换器还有:
str:匹配任何非空字符串,不包括路径分隔符'/'。表达式中不包含转换器,则默认为str。
int:匹配零或任何正整数。返回一个int。
slug:匹配由ASCII字母或数字组成的字符串,以及横线和下划线字符。例如, building-your-1st-django_url。
uuid:匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,并且字母必须是小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。
path:匹配任何非空字符串,包括路径分隔符 '/',可以匹配完整的URL路径,而不仅仅是URL路径的一部分str,使用时要谨慎,因为可能造成后续的所有url匹配都失效。
------------恢复内容开始------------
1、工作原理
django通过urlconf来映射视图函数,只区分路径,不区分http方法
- Django确定要使用的根URLconf模块,一般是在settings中的ROOT_URLCONF设置的值。
- Django加载该URLconf模块并查找变量 urlpatterns,它是一个列表django.urls.path() 和 / 或django.urls.re_path()实例。根据列表的实例查找相关的路劲。
- Django按顺序遍历每个URL模式,并停在与请求的URL匹配的第一个URL模式,后面相同的模式不会再进行匹配。
- 如果某个URL模式匹配成功,Django就会导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的视图方法)。
2、简单示例:
from django.urls import path from . import views urlpatterns = [ path('blog/2003/', views.special_2003), path('blog/<int:year>/', views.year_archive), path('blog/<int:year>/<int:month>/', views.month_archive), path('blog/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
在上述路由中,有几点需要注意:
(1)从URL中捕获,使用尖括号。
(2)捕获的值可以包含转换器,如/<int:year>/,前面的int表示只能是整数参数,year是参数的名称,用于视图函数的参数传递
(3)path的路径前不需要再添加“/”,
(4)示例说明
blog/2003/匹配的是path('blog/2003/', views.special_2003),而blog/2005/匹配的是path('blog/<int:year>/', views.year_archive),
3、格式转换器
在上面的示例中,我们已经看到了int这个格式转换器的用法,格式转换器还有:
str:匹配任何非空字符串,不包括路径分隔符'/'。表达式中不包含转换器,则默认为str。
int:匹配零或任何正整数。返回一个int。
slug:匹配由ASCII字母或数字组成的字符串,以及横线和下划线字符。例如, building-your-1st-django_url。
uuid:匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,并且字母必须是小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。
path:匹配任何非空字符串,包括路径分隔符 '/',可以匹配完整的URL路径,而不仅仅是URL路径的一部分str,使用时要谨慎,因为可能造成后续的所有url匹配都失效。
4、自定义格式转换器
转换器包含以下类:
一个regex类属性,作为一个re匹配字符串。
to_python(self, value)方法,它处理匹配的字符串转换成要传递到视图函数的类型。
o_url(self, value)方法,用于处理将Python类型转换为URL中使用的字符串。
转换器的定义方式如下:
(1)新建一个converters.py文件,在文件中定义一个类,使用to_python()和to_url()方法处理
class YearConverter(object): regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value
(2)使用register_converter()方法在URLconf中注册自定义转换器类 :
在需要注册的url.py文件中注册,先从django.urls中导入register_converter,同时导入自定义的类注册
from django.urls import register_converter, path from . import converters, views
# 注册自定义的转换器 register_converter(converters.YearConverter, 'yyyy') urlpatterns = [ path('blog/2003/', views.special_2003), path('blog/<yyyy:year>/', views.year_archive) ]
5、正则表达式的使用
使用正则表达式匹配路径时,使用re_path()。
在python正则表达式中,命名正则表达式的语法是(?P\<year>pattern),year是组的名称,pattern是需要匹配的模式。
from django.urls import path, re_path from . import views # url() 是 re_path 的别名,不推荐使用 urlpatterns = [ path('blog/2003/', views.special_2003), path('blog/<int:year>/', views.year_archive), re_path(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive), re_path(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), re_path(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail), ]
在上述正则表达式中:
^表示匹配开头,$表示匹配结束。
[0-9]{4}表示匹配4位0到9的数。
6、错误处理
- handler400- 状态码400
- handler403- 状态码403
- handler404- 状态码404
- handler500- 状态码500
(1)setting中修改设置
DEBUG = False ALLOWED_HOSTS = ['*', ]
(2)在主应用urls中配置
# blog表示子应用名 handler404 = "blog.views.page_not_found"
(3)在视图函数中定义以下函数
def page_not_found(request, exception): return HttpResponse('这是一个自定义的404错误页面')
我们看一下页面显示结果:当url找不到时,便会展示我们定义的404错误信息。
7、应用其他url调度器
在同一个url中,为了避免重复的路由输入,可以采用多个patterns的方法,示例如下:
from django.urls import include, path """原生代码: urlpatterns = [ path('blog/reports/', credit_views.report), path('blog/reports/<int:id>/', credit_views.report), path('blog/charge/', credit_views.charge), ] """ # 修改后的代码 blog_patterns = [ path('reports/', credit_views.report), path('reports/<int:id>/', credit_views.report), path('charge/', credit_views.charge), ] urlpatterns = [ path('blog/', include(blog_patterns)), ]
采用include()的方法
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ] # 修改为: from django.urls import include, path from . import views urlpatterns = [ path('<page_slug>-<page_id>/', include([ path('history/', views.history), path('edit/', views.edit), path('discuss/', views.discuss), path('permissions/', views.permissions), ])), ]
7、URL反向解析
(1)url调度器除了从用户发起请求,到匹配对应的view,还能在python程序中调用进行匹配,通过 path或re_path 中 的name属性进行解析。
在模板中,使用url模板标签,在url中,使用了name属性
from django.urls import path from . import views urlpatterns = [ #... path('blog/<int:id>/', views.id_archive, name='id-archive'), #... ]
在HTML模板中,我们可以使用url标签进行解析,方法示例如下:
<a href="{% url 'id-archive' 20 %}">20 Archive</a> <ul> {% for idvar in id_list %} <li><a href="{% url 'id-archive' idvar %}">{{ idvar }} Archive</a></li> {% endfor %} </ul>
href="{% url 'id-archive' 20 %}中"id-archive"就是name的属性。
(2)在Python代码中(主要是views视图中),使用 reverse() 函数。
from django.urls import reverse from django.http import HttpResponseRedirect def redirect_to_id(request): # ... num = 20 # ... return HttpResponseRedirect(reverse('news-year-archive', args=(num,)))
使用reverse进行重定向,完成url的一个跳转链接。
(3)在模型实例中,使用 get_absolute_url() 方法.
在模型中的实现方法如下:
def get_absolute_url(self): from django.urls import reverse return reverse('new-id-archive', args=[str(self.id)])
在模板中的实现方法如下:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
在上述实现方法中,"new-id-archive"是name属性的值,args是传入的参数值
8、命名空间
主要用于配合url反向解析使用,多个不同的urls文件中可能配置同名的name,那么为了进行区分,给不同的urls进行不同的命名,同一个项目下命名空间一定不能重复。
在url调度器的模块中,使用app_name = "名字"来命名。
from django.urls import path from . import views # 定义,一般命名空间和子应用名相同,便于记忆 app_name = 'blog' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), ... ]
当使用了命名空间之后,调用时必须有命名空间的前缀,其方法如下所示:
def test_app_name(request): return HttpResponseRedirect(reverse('blog:index'))
'blog:index',blog表示命名空间的名字,index表示name属性的值
命名空间的嵌套使用,嵌套与patterns中,如下所示:
from django.urls import path from . import views # 定义命名空间,一般命名空间名和子应用名相同,便于记忆 app_name = 'blog' blog_patterns = ( [ path('app_name/', views.app_name, name='app_name'), ], # 此处就是嵌套的命名空间 'reading' ) urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), path('reading/', include(blog_patterns)), ... ]
在模板中使用嵌套空间的方法
<a href="{% url 'blog:reading:app_name' %}">点击链接</a>
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>