4.Django路由系统

Django路由系统

  1. URL调度器

    • Django 允许自由地设计你的URL,不受框架束缚。Django认为,对于高质量的Web 应用来说,使用简洁、优雅的URL 模式是一个非常值得重视的细节。
    • 为了给一个应用设计URL,你需要创建一个Python 模块,通常被称为URLconf(URL configuration)。URLconf也被称作路由系统,这个模块是纯粹的Python 代码,包含URL 模式(简单的正则表达式)到Python 函数(你的视图)的简单映射。可以把URLconf比作书的目录。

  1. URLconf的基本格式

    • 在Django项目名称目录(以项目名称为:"Django" 为例)的urls.py文件中,找到urlpatterns

      from django.urls import path
      from app import views   # 从app中导入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:slug>/', views.article_detail),
      ]
      
    • 注意:

      • 要从 URL 中取值,使用尖括号。
      • 捕获的值可以选择性地包含转换器类型。比如,使用 <int:name> 来捕获整型参数。如果不包含转换器,则会匹配除了 / 外的任何字符。
      • 路径的最前面不需要添加反斜杠,因为每个 URL 都有。比如,应该是 articles 而不是 /articles 。

  1. URLconf的路径转换器

    下面的路径转换器在默认情况下是有效的:

    • str - 匹配除了 '/' 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。
    • int - 匹配0或任何正整数。返回一个 int 。
    • slug - 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site
    • uuid - 匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写。比如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID 实例。
    • path - 匹配非空字段,包括路径分隔符 '/' 。它允许你匹配完整的 URL 路径而不是像 str 那样只匹配 URL 的一部分。

  1. URLconf注册自定义的路径转换器

    对于更复杂的匹配需求,可以定义自己的路径转换器。

    转换器是一个类,包含如下内容:

    • 字符串形式的 regex 类属性。

    • to_python(self, value) 方法,它处理匹配的字符串转换为应该传递到函数的类型。如果没有转换为给定的值,它应该会引发 ValueErrorValueError 被解释为不匹配,因此向用户发送404响应。

    • to_url(self, 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
      
    • 在 URLconf 中使用 register_converter() 来注册自定义的转换器类:

      from django.urls import path, register_converter
      from app import converters, views
      
      register_converter(converters.FourDigitYearConverter, 'yyyy')
      
      urlpatterns = [
          path('articles/2003/', views.special_case_2003),
          path('articles/<yyyy:year>/', views.year_archive),
          ...
      ]
      

  1. URLconf使用正则表达式

    如果路径和转化器语法不能很好的定义你的 URL 模式,你可以可以使用正则表达式。如果要这样做,请使用 re_path() 而不是 path()

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

    这里是先前 URLconf 的一些例子,现在用正则表达式重写一下:

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

    这实现了与前面示例大致相同的功能,除了:

    • 将要匹配的 URLs 将稍受限制。比如,10000 年将不在匹配,因为 year 被限制长度为4。
    • 无论正则表达式进行哪种匹配,每个捕获的参数都作为字符串发送到视图。

    当从使用 path() 切换到 re_path() (反之亦然),要特别注意,视图参数类型可能发生变化,你可能需要调整你的视图。


  1. URLconf使用未命名的正则表达式组

    • 还有命名组语法,例如 (?P<year>[0-9]{4}) ,你也可以使用更短的未命名组,例如 ([0-9]{4})

    • 不是特别推荐这个用法,因为它会更容易在匹配的预期含义和视图参数之间引发错误。

    • 在任何情况下,推荐在给定的正则表达式里只使用一个样式。当混杂两种样式时,任何未命名的组都会被忽略,而且只有命名的组才会传递给视图函数。


  1. URLconf中包含其他的URLconfs

    • 在任何时候,你的 urlpatterns 都可以 "include" 其它URLconf 模块。这实际上将一部分URL 放置于其它URL 下面。例如,下面是URLconf Django website 自己的URLconf 中一个片段。它包含许多其它URLconf:

      from django.urls import include, path
      
      urlpatterns = [
          # ... snip ...
          path('community/', include('aggregator.urls')),
          path('contact/', include('contact.urls')),
          # ... snip ...
      ]
      
    • 每当 Django 遇到 include() ,它会将匹配到该点的URLconf的任何部分切掉,并将剩余的字符串发送到包含的URLconf进行进一步处理。另一种可能性是通过使用 path() 实例的列表来包含其他 URL 模式。比如,看这个 URLconf:

      from django.urls import include, path
      
      from apps.main import views as main_views
      from credit import views as credit_views
      
      extra_patterns = [
          path('reports/', credit_views.report),
          path('reports/<int:id>/', credit_views.report),
          path('charge/', credit_views.charge),
      ]
      
      urlpatterns = [
          path('', main_views.homepage),
          path('help/', include('apps.help.urls')),
          path('credit/', include(extra_patterns)),
      ]
      
    • 在这个例子中, /credit/reports/ URL将被 credit.views.report() 这个Django 视图处理。这种方法可以用来去除URLconf 中的冗余,其中某个模式前缀被重复使用。例如,考虑这个URLconf:

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

  1. URL的命名和URL的反向解析

    • URLconf中支持给URL匹配规则和URL匹配模式起一个名字,这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。例如,我们在urls.py中:

      from django.urls import path
      from app import views
      
      urlpatterns = [
          #...
          path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
          #...
      ]
      
    • 在模板里面可以这样引用:

      <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
      {# Or with the year in a template context variable: #}
      <ul>
      {% for yearvar in year_list %}
      <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
      {% endfor %}
      </ul>
      
    • 在views函数中可以这样引用:

      from django.http import HttpResponseRedirect
      from django.urls import reverse
      
      def redirect_to_year(request):
          # ...
          year = 2006
          # ...
          return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
      

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342