django2.2-路由层详解

系列文章目录

一、路由层基础

django的路由写在urls.py中的urlpatterns列表中。
当收到请求时,依次匹配每个URL模式,在与所请求URL相匹配的第一个路由停下来,接着执行对应的视图代码。

  • 添加路由:

    在urls.py文件中:

    from django.contrib import admin
    from django.urls import path
    
    # 导入视图模块
    from app名 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),  # 系统自带,管理后台相关,不要管
        # 添加路由
        path('url后缀部分/', views.视图函数),
    ]
    

1. 捕获参数

使用get方法提交的数据,保存在url中,因此我们需要通过一些方法来捕获这些数据,而方法就是使用django的<>语法。

比如捕获数字:

 path('index/<int:number>/', views.视图函数),

<>用来捕获参数,冒号前面的int是路径转换器,用来匹配数字,它是可选的,不写的话默认转换为str路径转换器。

捕获到的参数会以关键字参数的形式传递给视图,参数名为冒号后面的内容

2. 路径转换器

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

二、自定义路径转换器

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

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

  • 字符串形式的 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 . import converters, views

# 注册转换器
register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<yyyy:year>/', views.year_archive),
    ...
]

三、re_path()方法

python中正则表达式的语法:传送门

  • re_path()方法:

    path()方法的url模式是固定的字符串,不能使用正则表达式。
    如果需要使用正则表达式,可以改用re_path()方法。该方法需要导入:from django.urls import re_path

    但是,使用正则表达式的re_path有个缺点,比如:

    re_path(r'in', views.in),
    re_path(r'index', views.index),
    

    在url后缀为index的情况下,依旧会先匹配到in,不再去匹配index,然后执行错误的index视图。

    解决方法为在匹配规则的后面加一个斜杠即可:

    re_path(r'^in/$', views.in),
    re_path(r'^index/$', views.index),
    

    并且,为了更加严谨起见,最好在加一个^$表示严格以该模式作为起始和结束。

  • 空白url的正确写法:

    另外,我们通常会将没有后缀的url,也当作主页处理,让其与index/使用同一个视图。但匹配规则写空字符串'',反而会匹配到所有的url后缀,不能这样用。应该采用下面的写法:

    re_path(r'^$', views.index),  # 匹配真正的空白url后缀
    
  • 取消url自动加斜杠:

    如果我们在浏览器打开的url后缀为aaa,而路由中的匹配规则为aaa/时。由于aaa后面缺少了一个斜杠,照理来说应该匹配不到url模式。但事实却与之相反,aaa不仅能匹配到aaa/,而且在浏览器的地址栏中,aaa的后面被自动加了/

    这是由于django帮我们做了优化,在aaa匹配不到url模式时,它会自动给aaa加一个斜杠,使其成为aaa/,然后请求浏览器重定向到该url,如果成功匹配到,就万事大吉,执行对应视图代码。如果匹配不到,这时候才会返回404。

    该功能是默认开启的,如果想要取消该功能,可以在settings.py中加入下面的内容:

    APPEND_SLASH = False  # 默认为True
    

四、有名分组、无名分组

如果想在re_path()方法中提取url中的内容,可以使用正则表达式中的分组语法。

正则表达式分组:

(模式)表示分组,即捕获模式匹配到的字符串。
(?P<名称>模式)表示分组并命名,即捕获模式匹配到的字符串并命名。

  • 无名分组:

    比如从url中提取数字:

    re_path(r'list/(\d+)/', views.list)
    

    捕获到的数字会被直接当作位置参数传递给视图,因此,需要对应的参数来接收,并且要注意捕获分组的顺序与形参的顺序要一致

    def list(request, number):
        pass
    
  • 有名分组:

    还是以提取数字为例,只不过这次采用给分组命名的形式捕获字符串:

    re_path(r'list/(?P<number>\d+)/', views.list)
    

    这次,参数会以关键字参数的形式传递给视图,而视图就不需要按照位置接收参数,形参写分组的名称即可。分组的名称此时就相当于变量名。

    注意:无名分组和有名分组不能混用!!!

五、反向解析

  • 反向解析的作用:
    通过名称来反向动态获取url路径。这样可以避免url需要修改时,一个个地去修改url,只需到urls.py中修改一次即可。

1. 基本使用方法

先使用name参数,给路由起一个名字:

path('index/', views.view_index, name='name_index')

然后通过反向解析,得到'/index/'

<a href="{% url 'name_index' %}"></a>
<!-- 以上代码相当于下面的代码 -->
<a href="/index/"></a>

在视图中使用反向解析:

from django.urls import reverse
def my_view(request):
	reverse('name_index')  # 该方法的返回值为:/index/

2. url参数的传递

如果需要从url中捕获参数,那么在反向解析的时候,就要向reverse(){% url %}手动传递这些参数。根据位置参数和关键字参数两种捕获方法,有以下两种对应的传参方法:

  • 位置参数:

    在路由中:

    re_path('index/(\d+)/', views.view_index, name='name_index')
    

    在模板中:

    <a href="{% url 'name_index' 888 %}"></a>
    <!-- 以上代码相当于下面的代码 -->
    <a href="/index/888/"></a>
    
    <!-- 对于需要用模板语法获取的参数,不需要写 {{ }} -->
    
    <!-- 错误写法 
    <a href="{% url 'name_index' {{ user.id }} %}"></a> -->
    
    <!-- 正确写法 -->
    <a href="{% url 'name_index' user.id %}"></a>
    

    在视图中:

    def my_view(request):
        reverse('name_index', args=(888,))  # 该方法的返回值为:/index/888/
    

    注意:args参数接收的是元组类型实参,所以在只有一个参数的情况下,要加一个额外的英文逗号。

  • 关键字参数:

    在路由中:

    path('index/<int:id>/', views.view_index, name='name_index')
    

    在模板中:

    <a href="{% url 'name_index' id=888 %}"></a>
    <!-- 以上代码相当于下面的代码 -->
    <a href="/index/888/"></a>
    
    <!-- 对于需要用模板语法获取的参数,不需要写 {{ }} -->
    <a href="{% url 'name_index' id=user.id %}"></a>
    

    在视图中:

    def my_view(request):
        reverse('name_index', kwargs={'id':888})  # 该方法的返回值为:/index/888/
    

    在关键字参数的情况下,使用位置参数下的传参方法是可以的,只不过上面的方式更加正规。

六、路由分发

django的每一个app,也可以拥有自己的templates文件夹、static文件夹和urls.py文件。

  • 路由分发的作用:
    当一个django项目中的url特别多的时候,可以将url写在app的路由中,而在总路由(项目的urls.py)中指向对应app的路由,以此来减轻总路由的压力。

  • 使用方法:

    手动在app文件夹下创建urls.py文件,并将项目路由文件中的内容复制过来,然后删除不需要的内容。

    比如,在项目urls.py中,只要是url后缀是index/开头的,都去appindex_app中的urls.py中进行匹配;login/开头的,都去applogin_app下的urls.py中进行匹配;

    则总路由的写法为:

    from django.urls import include, path
    
    urlpatterns = [
        path('index/', include('index_app.urls')),
        path('login/', include('login_app.urls'))
    ]
    

    上面的代码,**会将url后缀中的开头部分截取掉,将剩余部分发送给对应app的urls去处理。**比如,index/xxx/login/yyy/截取后为xxx/yyy/。然后app中的路由,就按照路由的一般写法来就可以了。

    要注意的是:使用re_path()时,正则表达式不能写$,因为写了$,就不能匹配到除开头部分以外的内容了。

七、名称空间

假设我们有两个app,这两个app下都有主页index,并且都给路由起了相同的名字index,那么在反向解析的时候,django就分不清index指的是哪个app下的主页了。而名称空间就是用来解决这一问题的。

  • 总路由:

    假设app的名称为app01

    path('index/', include(('app01.urls', 'app01'), namespace='ind'))
    

    与之前include()的参数不同的是,第一个参数改为了元组,元组内的元素指定了urls的位置和app的名称。第二个参数namespace用来设置名称空间。

  • app内的子路由:

    path('yyy/', views.index, name='y')
    
  • 反向解析:

    视图中:

    reverse('ind:y')
    

    模板中:

    {% url 'ind:y' %}
    

八、伪静态

伪静态就是将一个动态网页伪装成静态网页。目的是增大该网站的SEO(Search Engine Optimization,汉译为搜索引擎优化)力度,增加被搜索引擎搜到的概率,提高搜索引擎的展示优先级别。当然,无论我们怎么优化,还是干不过人民币玩家的。

  • 实现伪静态:

    只需要在url中加一个.html后缀即可。

    path('index.html/', views.index)
    

下一篇

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花_城

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值