在开始前需要先弄清楚几个概念
- 路由
- 路由表
- 路由分发
django 路由介绍
在介绍 django 的路由之前,你知道什么是路由吗?
路由
路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。路由发生在 OSI 网络参考模型中的第三层即网络层
❝
来自维基百科
就像当你用地图的时候,你输入当前地址,输入目的地址,然后就会出来一条路径信息,告诉你应该怎么走,对于 django 同样也是如此,当我们在浏览器上输入一段网址时,这个网址就是我们的目的地,而源地址就是我们的浏览器。
以上就是关于路由的介绍,只需要知道:源、目标
路由表
路由表是一个存储在路由器或者联网计算机中的电子表格(文件)或类数据库。路由表存储着指向特定网络地址的路径
说白了路由表存储了很多条的路由信息,就比如说去一个陌生城市,买了一张地铁线路图,这张图就好比一张路由表,这张图里记录了很多的错综复杂的地铁线路信息,比如在北京,我们现在互联网聚集地:西二旗,我们想去故宫,那么我们就可以查阅这张图,这样我们就知道了线路,又比如你今天去故宫,明天去中关村,后天去北京南站,总之不管你去哪,我们都可以在这张图里找到我们的出行线路,这张图就是我们的路由表
路由分发
还是坐地铁啊,当我们在地铁线路图(路由表)里找到了我们的线路信息(路由)之后,我们乘坐地铁来到了这个地铁站,但是作为一个正常人,你想想我们去地铁站干毛线,我们坐地铁的最终目的不就是去一个确切的地方吗,比如我们早晨上班,同样都是坐到某站就下次,但是大家的最终目的地都不一样,有的人去 A 公司,有的去 B 公司,有的人去 A 酒吧,有的去 B 保健,每一个人都是一条路由,而每个人去的最终目的地都是路由分发的结果
简而言之一句话就是:通过路由表查找路由信息,根据路由信息最终达到目的地。
django 路由
django 中也是这个道理,django 里存放着一张路由表,当请求经过这个路由表时,根据请求内容找到路由信息,随后进行分发,分发到最终一个一个的函数中,函数最终才是我们的目的地。
django 的路由表实际上是保存到一个列表里的: urlpatterns
, 如下所示
# urls.py
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
下面将结合示例来介绍
在介绍之前,首先创建一个 django 项目
# 创建一个项目
django-admin startproject mysite2
django 路由示例
最简单的一个路由
请求/articles/2021/11
来获取某一天的文章信息
- 首先创建一个视图函数
这里用到了一个HttpResponse
类,用于对返回给浏览器的数据进行封装,返回一个HttpResponse
对象
# 没有此文件,就创建下
# mysite2/views.py
# 导一下HttpResponse包
from django.http import HttpResponse
def article_detail(request):
return HttpResponse("文章信息")
- 建立路由映射
这里模拟一个文章归档目录的请求,所有的文章归档情况都在articles/
目录下,然后用时间进行区分,这里把时间写死,同时思考下如果我们要看 2021 年所有月份的文章咋办
from django.contrib import admin
from django.urls import path
from .views import article_detail
urlpatterns = [
path('admin/', admin.site.urls),
path('articles/2021/11/', article_detail)
]
- 访问测试
将我们的 django 项目运行起来
python3 manage.py runserver
浏览器访问测试
http://127.0.0.1:8000/articles/2021/11/
这样一整套流程下来,我们已经大致了解了下流量的访问顺序,大致就是:
- 浏览器发起请求
- django 接收请求
- 进入 urls.py 中
- 查找 urlpatterns 里的路由
- 找到一条路由,并进入到相应的视图函数中
- 进入视图函数,开始处理请求,并构造一个响应,返回给浏览器
正则匹配路由
上面的案例中有一个问题就是,当我们请求一整年的月份信息时,我们要设置一堆路由,大概就是下面这种
urlpatterns = [
path('articles/2021/1', article_detail01),
path('articles/2021/2', article_detail02),
path('articles/2021/3', article_detail03),
path('articles/2021/4', article_detail04)
]
这样倒是可以,当我们肯定不能这么干,我们可以通过使用 django 的re_path
方法来通过设置一些正则来进去匹配,就像下面这样的:
from django.urls import path, re_path
from .views import article_detail
urlpatterns = [
re_path('articles/(\d{4})/(\d{1,2})', article_detail)
]
❝
注意:正则一定要写到小括号()里,表示捕获组的意思
那这样我们修改下视图函数
def article_detail(request, year, month):
print(year, month)
return HttpResponse(f"{year}年{month}月")
再次运行下项目,访问测试:
http://127.0.0.1:8000/articles/2021/10/
有名分组路由
有名分组是对上面的一个简单补充,很简单,就是通过设置组名,在传参的时候,可以指定组名进行传承
修改路由信息
# 修改路由
urlpatterns = [
re_path('articles/(?P<year>\d{4})/(?P<month>\d{1,2})', article_detail)
]
视图函数不需要修改,但是需要注意,视图函数中的关键字参数名称不能边,必须和我们设置的组名保持一致才行。
路由分发
通过上面的示例,我们想象一下,加入有几百条路由信息,那么是不是urlpatterns
这个列表会非常的长,维护起来是不是特别费劲,再结合我们一开始讲的那个坐地铁的例子,我们可不可以先到站,这个人到西二旗站,另一个人到中关村站,我们先把请求进行分组,不同的请求进入到不同的组中。
django 里肯定可以这样做,通过创建不同功能的应用,然后把请求分发到不同的应用里,最后在将不同的应用请求映射到不同的视图函数中,这样不仅可以解耦,维护起来也会清晰
创建一个应用
创建一个 user 应用,这个应用简单输出一下看下效果
python3 manage.py startapp user
创建好应用之后,我们需要创建urls.py
的文件,然后设置好我们的子路由的一些信息.
进入到user
这个应用中
# user/urls.py
from django.urls import path
from .views import user_list
urlpatterns = [
path('list/', user_list)
]
user
应用的视图函数
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def user_list(request):
return HttpResponse("this is a user app")
然后最后我们设置下总路由,回到mysite2
下的urls.py
中
from django.contrib import admin
from django.urls import path, re_path, include
from .views import article_detail
urlpatterns = [
path('admin/', admin.site.urls),
# path('articles/2021/11/', article_detail),
re_path('articles/(?P<year>\d{4})/(?P<month>\d{1,2})', article_detail),
path('user/', include('user.urls'))
]
这里我们创建的应用名为:user
,然后我们这里设置的路由为user/
,意思是所有是user/
开头的请求都会被转发到user.urls
中,而如何转发,则用include
方法就可以了。
我们再去访问测试,结果如下
路由转换器
对于一些更复杂的匹配需求,django 提供了自定义转换器。
首先转换器是一个类,我们需要定义一个类,类中包含以下内容:
regex
类属性,定义一个正则表达式to_python(self, value)
方法,将 url 中的值进行转换,然后传递给视图函数to_url(self, value)
方法,在做 URL 反转时,将传递进来的参数转换后拼接成一个正确的 url
❝
url 反转就是,一般我们都是通过 url 来访问视图函数,现在我们知道视图函数,想找到这个视图函数对应的 url,这个就叫反转 url
接下来我们创建一个应用,然后在这个应用里定义一个打印手机号的视图函数
- 启动一个应用
python3 manage.py startapp mobile
2)设置主路由
from django.contrib import admin
from django.urls import path, re_path, include
from .views import article_detail
urlpatterns = [
path('admin/', admin.site.urls),
# path('articles/2021/11/', article_detail),
re_path('articles/(?P<year>\d{4})/(?P<month>\d{1,2})', article_detail),
path('user/', include('user.urls')),
path('mobile/', include('mobile.urls')) # 指向新创建的mobile应用
]
- 定义一个转换器
我们直接在新创建的 mobile 应用中的urls.py
里定义
from django.urls import path, register_converter
from .views import print_mobile
class MobileConverter:
# 定义正则表达式
regex = '1[3-9]{2}\d{8}'
def to_python(self, value):
return int(value)
register_converter(MobileConverter, 'mobile')
urlpatterns = [
path('info/<mobile:mobile_number>', print_mobile)
]
❝
注意这里
<mobile:mobile_number>
这俩的区别,mobile
这个是我们定义的转换器中传入参数的一个名称,而后面的mobile_number
是我们要传给视图函数的参数。
- 创建视图函数
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def print_mobile(request, mobile_number):
return HttpResponse(f"Your mobile number is {mobile_number}")
访问测试:
如果我们试着输一个 12 位的手机号,这里就会直接报错
反向解析
反向解析的一个好处就是随着项目功能的增加,路由也随之增多,当某些 url 频繁更改时,那么随之而来的就是视图层、模板层可能都要随之改动,这样非常不利于维护,所以我们通过设置反向解析,当路由层的 url 发生变化时,视图层和模板层可以动态的进行反向解析,从而找到更改后的 url,通过这样的方式,我们可以免去修改 url 的操作。
下面只以视图层为例
- 首先给路由设置一个 name
from django.contrib import admin
from django.urls import path, re_path, include
from .views import index, login
urlpatterns = [
path('index/', index, name="index"),
path('login/', login)
]
这里我们创建了一个指向 index 的路由,并给这个路由设置了一个名称, 同时为了简单的测试,又创建了一个 login 的路由,在访问 login 的时候,会进行重定向,最终会指向首页
- 创建视图函数
from django.shortcuts import HttpResponse, redirect, reverse
def index(request):
return HttpResponse("This is a index")
def login(request):
return redirect(reverse("index"))
- 访问测试
这里访问 login 即可,正常来说会 302 到 index 上,我们看下效果
接下来修改 index 的路由
urlpatterns = [
path('indexs/', index, name="index"),
path('login/', login)
]
再次访问
原创文章,作者:Rosmontics,如若转载,请注明出处:https://rosmontis.com/archives/189