zoukankan      html  css  js  c++  java
  • Django之路由系统

    Django是如何处理一个请求

    官方文档

    1、Django确定要使用的根URLconf模块。通常,这是ROOT_URLCONF设置的值,但是如果传入 HttpRequest对象具有urlconf 属性(由中间件设置),则将使用其值代替 ROOT_URLCONF设置。

    2、Django加载该Python模块并查找变量 urlpatterns这是django.urls.path() 和/或django.urls.re_path()实例的Python列表

    3、Django按顺序运行每个URL模式,并在与请求的URL匹配的第一个停止。

    4、一旦其中一个URL模式匹配,Django就会导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的视图)。该视图将传递以下参数:

    • 的实例HttpRequest
    • 如果匹配的URL模式未返回命名组,则来自正则表达式的匹配项将作为位置参数提供。
    • 关键字参数由与路径表达式匹配的任何命名部分组成,并由或 的可选kwargs参数中指定的任何参数覆盖 django.urls.path()django.urls.re_path()

    5、如果没有URL模式匹配,或者在此过程中的任何时候引发异常,Django都会调用一个适当的错误处理视图。请参阅下面的错误处理。

    例子: 

     1 from django.urls import path
     2 
     3 from . import views
     4 
     5 urlpatterns = [
     6     path('articles/2003/', views.special_case_2003),
     7     path('articles/<int:year>/', views.year_archive),
     8     path('articles/<int:year>/<int:month>/', views.month_archive),
     9     path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
    10 ]

      

    • 捕获的值可以选择包括转换器类型。例如,用于 <int:name>捕获整数参数。如果不包括转换器/,则匹配字符以外的任何字符串
    • 无需添加斜杠,因为每个URL都有该斜杠。例如articles,不是/articles
    • 要从URL捕获值,请使用尖括号。

    注意:在使用如<int:year>传递参数的时候,传递的参数一定要被对应的函数接收。

    请求示例:

    • 请求/articles/2005/03/匹配列表中的第三个条目。Django将调用该函数 views.month_archive(request, year=2005, month=3)
    • /articles/2003/会匹配列表中的第一个模式,而不是第二个,因为这些模式是按顺序测试的,而第一个是第一个通过的测试。随意利用命令来插入类似这样的特殊情况。在这里,Django将调用该函数 views.special_case_2003(request)
    • /articles/2003 不会与任何这些模式匹配,因为每种模式都要求URL以斜杠结尾。
    • /articles/2003/03/building-a-django-site/将匹配最终模式。Django将调用该函数 views.article_detail(request, year=2003, month=3, slug="building-a-django-site")

    路径转换器

    默认情况下,以下路径转换器可用:

    • str-匹配任何非空字符串,但路径分隔符除外'/'如果表达式中不包含转换器,则为默认设置。
    • int-匹配零或任何正整数。返回一个int
    • slug-匹配由ASCII字母或数字以及连字符和下划线字符组成的任何条形字符串。例如, building-your-1st-django-site
    • uuid-匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,并且字母必须小写。例如,075194d3-6885-417e-a8a8-6c931e272f00返回一个 UUID实例。
    • path-匹配任何非空字符串,包括路径分隔符 '/'这样,您就可以与完整的URL路径进行匹配,而不仅仅是与URL路径的一部分进行匹配str

    使用正则表达式

    如果路径和转换器语法不足以定义URL模式,则还可以使用正则表达式。为此,请使用 re_path()代替path()

    在Python正则表达式中,命名正则表达式组的语法为(?P<name>pattern),其中name是组的名称,并且 pattern是匹配的某种模式。

    这是前面的示例URLconf,使用正则表达式重写:

    1 from django.urls import path, re_path
    2 
    3 urlpatterns = [
    4     path('articles/2003/', views.special_case_2003),
    5     re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    6     re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    7     re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[w-]+)/$', views.article_detail),
    8 ]

     这可以完成与上一个示例大致相同的操作,除了: 

    • 将要匹配的确切URL受到更多限制。例如,年份10000将不再匹配,因为年份整数被限制为正好是四位数长。
    • 无论正则表达式进行哪种匹配,每个捕获的参数都将作为字符串发送到视图。 

    当从使用path()切换为使用 re_path()时,特别重要的是要注意视图参数的类型可能会更改,因此您可能需要调整视图。 

    嵌套参数

     考虑以下URL模式,这些URL模式可以选择采用page参数:

    urls.py中:
    1
    from django.urls import path, re_path 2 from app01 import views 3 4 urlpatterns = [ 5 path('admin/', admin.site.urls), 6 re_path(r'^blog/(page-(d+)/)?$', views.test), 7 re_path(r'^comments/(?:page-(?P<page_number>d+)/)?$', views.test2), 8 ]
     views.py中:
    1
    def test(request, arg1, arg2): 2 print(request) 3 print(arg1) 4 print(arg2) 5 return HttpResponse("空页面") 6 7 8 def test2(request, page_number): 9 print(request) 10 print(page_number) 11 return HttpResponse("空页面2")

     例如:

    blog/page-2/将导致与匹配blog_articles两个位置参数:page-2/2。在视图函数中要接收这两个位置参数。

    comments/page-2/与关键字参数 page_number设置为2 匹配。在视图函数中只需要接收page_number一个参数即可。 

    分组命名匹配 

    在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

    在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

    注意:分组命名匹配中视图函数在接收参数中必须写入分组关键字参数名。

    根据参数类型分组匹配:

    1 urlpatterns = [
    2    path('articles/2003/', views.special_case_2003),
    3    path('articles/<int:year>/', views.year_archive),
    4    path('articles/<int:year>/<int:month>/', views.month_archive),
    5    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
    6 ]

     正则分组命名匹配:

    正则分组命名匹配获取的全是字符串类型

    1 urlpatterns = [
    2    path('articles/2003/', views.special_case_2003),
    3    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    4    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    5    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[w-]+)/$', views.article_detail),
    6  ]

     include其他的URLconfs

    当包含的url太多,或者对url进行分不同功能app分类管理时,就需要用到包含其他URLconfs的方法。

     path('app01/', include(('app01.urls',"app01"), namespace="app01")),
     path('app02/', include(('app02.urls', "app02"), namespace="app02")),

    传递额外的参数给视图函数(了解)

    path()函数可以使用可选的第三个参数,该参数应该是传递给view函数的额外关键字参数的字典。

    urlpatterns = [
        path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
    ]

    将额外的选项传递给include()

    同样,您可以将额外选项传递给include(),所包含的URLconf中的每一行都将传递额外选项。

    例如,这两个URLconf集在功能上是相同的:

    设置一:

     1 from django.urls import include, path
     2 
     3 urlpatterns = [
     4     path('blog/', include('inner'), {'blog_id': 3}),
     5 ]
     6 
     7 # inner.py
     8 from django.urls import path
     9 from mysite import views
    10 
    11 urlpatterns = [
    12     path('archive/', views.archive),
    13     path('about/', views.about),
    14 ]

    设置二:

     1 # main.py
     2 from django.urls import include, path
     3 from mysite import views
     4 
     5 urlpatterns = [
     6     path('blog/', include('inner')),
     7 ]
     8 
     9 # inner.py
    10 from django.urls import path
    11 
    12 urlpatterns = [
    13     path('archive/', views.archive, {'blog_id': 3}),
    14     path('about/', views.about, {'blog_id': 3}),
    15 ]

    URL的反向解析

    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

    • 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
    • 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

    第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。
    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

    • 在模板中:使用url模板标签。
    • 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
    • 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

    考虑下面的URLconf:

    1 from django.conf.urls import url
    2 
    3 from . import views
    4 
    5 urlpatterns = [
    6     # ...
    7     url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    8     # ...
    9 ]

     根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/

    你可以在模板的代码中使用下面的方法获得它们: 

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    
    <ul>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    </ul>

     在Python 代码中,这样使用:

    1 from django.http import HttpResponseRedirect
    2 from django.urls import reverse
    3 
    4 def redirect_to_year(request):
    5     # ...
    6     year = 2006
    7     # ...
    8     return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

     如果出于某种原因决定更改发布年度文章存档内容的URL,则只需要更改URLconf中的条目即可。

    在视图具有一般性质的某些情况下,URL和视图之间可能存在多对一关系。对于这些情况,在反向URL时,视图名称并不是一个足够好的标识符。阅读下一节以了解Django为此提供的解决方案。

    命名空间模式

    即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

    举个例子:

    project中的urls.py

    from django.conf.urls import url, include
     
    urlpatterns = [
        url(r'^app01/', include('app01.urls', namespace='app01')),
        url(r'^app02/', include('app02.urls', namespace='app02')),
    ]

    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')
    ]

    app02中的urls.py

    from django.conf.urls import url
    from app02 import views
     
    app_name = 'app02'
    urlpatterns = [
        url(r'^(?P<pk>d+)/$', views.detail, name='detail')
    ]

    现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

    语法:

    '命名空间名称:URL名称'

    模板中使用:

    {% url 'app01:detail' pk=12 %}

     views中的函数中使用:

    v = reverse('app01:detail', kwargs={'pk':11})

    这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

    遗留的问题:

    自定义路径转换器还没能成功运行。

  • 相关阅读:
    IPv4地址被用光,IPv6将接手
    杀猪盘
    大家都应该看看这个贴子,会让你心明眼亮。 注意到这些变化了吗?中国正在发生的100个变化,越往后读越震惊!
    区块链在中国怎么练?
    区块链到底是什么样的技术呢?
    2019感恩节
    人工智能、大数据、物联网、区块链,四大新科技PK,你更看好谁?
    vue遇见的问题(2)---imported multiple times(转载)
    drf-序列化器的理解
    Django rest_framework序列化many=True参数解释
  • 原文地址:https://www.cnblogs.com/newway644617704/p/13040066.html
Copyright © 2011-2022 走看看