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>

 

posted @ 2020-07-06 14:57  呆呆的clearlie  阅读(153)  评论(0编辑  收藏  举报