四方显神

导航

Django开发笔记(三)四件套一:路由控制器

这篇开始,正式进入Django语法学习。

一、路由的简单分组使用

Route路由, 是一种映射关系,路由是把客户端请求的url路径和用户请求的应用程序(这里意指django里面的视图)进行绑定映射的一种关系。但是,请求路径和视图函数不是一对一映射关系,也可以多个路径对应一个函数,不过没有一个路径对应多个函数。

在django中所有的路由最终都被保存到一个变量 urlpatterns.urlpatterns必须声明在主应用下的urls.py总路由中。这是由配置文件settings设置的。这个urlpatterns其实就是我们写的那个请求列表:

在django运行中,当客户端发送了一个http请求到服务端,服务端的web服务器则会从http协议中提取url地址, 从程序内部找到项目中添加到urlpatterns里面的所有路由信息的url进行遍历匹配。如果相等或者匹配成功,则调用当前url对象的视图方法。

调用当前url对象的视图方法,是Django在调用,同时给它传一个实参(request对象),所以上图第14行,其实是get_timer(request),这个request对象包含了我们每次请求的全部请求信息。

我们本身web开发就是网络编程,他是一定有有socket的,Django看不到socket是因为wsgi.py将socket封装好了,也就是其实请求来的时候,启动的就是wsgi.py文件。接下来wsgi.py主要做两件事:解析请求数据、封装响应。

那么就要给我们的经典图示加上一个前两篇没有的豆绿色框框了:

请求进来以后,一大堆请求头请求体,它会把所有的数据解析成request对象。Django进入urls.py的时候其实会把request传过去,叫一个实参调用,这也是为什么views.py里的每一个视图函数都有一个形参request的原因。

正则路由:

在给urlpatterns路由列表添加路由的过程中,django一共提供了2个函数给开发者注册路由:

from django.urls import path      # 字符串路由
from django.urls import re_path   # 正则路由,会把url地址看成一个正则模式与客户端的请求url地址进行正则匹配

# path和re_path 使用参数一致.仅仅在url参数和接收参数时写法不一样

简单分组:(将正则匹配的内容传到视图函数中)

在正则路由的时候涉及到一个分组的概念,用户请求进来后,前面匹配成功的东西要不要传过去,如果需要,就给它加个括号,这就是正则分组。

urlpatterns = [
path('articles/2012/12', article_detail), # re_path('articles/\d{4}/\d{2}', article_archive), # 没有分组,你的四位数字,两位数字都传不到其他地方 re_path('articles/(\d{4})/(\d{2})', article_archive) #分组了,那么对应的article_archive这个视图函数里就必须多两个

关于正则表达式,不用就忘,随用随看:正则表达式 – 教程 | 菜鸟教程 (runoob.com)

那正则学得好,反应就比较快,比如上面的代码,如果访问的url第二个参数只有一位(例如http://127.0.0.1:8000/articles/2018/11/8)就找不到页面了,使用正则解决只需要修改一下代码:

re_path('articles/(\d{4})/(\d{1,2})', article_archive)

既能匹配两位,也能匹配一位了。

解决优先匹配覆盖问题:

    re_path('articles/(\d{4})$', article_archive_by_year), #加个$就不会覆盖下面的那行了
    re_path('articles/(\d{4})/(\d{1,2})', article_archive_by_month)  # 分组了,那么此时article_archive这个视图函数里就必须过两个形参

二、Django路由的有名分组

有名分组就是在分组的时候给每个组起个名字。

在第一个小括号里写一个  ?p<>  尖括号里是分组名称

    re_path('articles/(?P<year>\d{4})$', article_archive_by_year),
    re_path('articles/(?P<month>\d{4})/(\d{1,2})', article_archive_by_month)

那流程就是:

请求路径:/articles/2001/11

re.findall("articles/(?P<month>\d{4})/(\d{1,2})","/articles/2001/11")

一旦匹配成功:

如果是简单分组:调用article_archive_by_month(request,2001,11) 位置传参

如果是有名分组:调用article_archive_by_month(request,year=2001,month=11) 关键字传参,不需要考虑形参顺序

三、Django路由分发

所谓路由分发,就是将我们的urls解耦到不同的应用中。路由分发一定要学会,因为我们在实际项目中会大量使用。简单好看,妙不可言。

语法:

1. Import the include() function: 
  from django.urls import include, path 2. Add a URL to urlpatterns:
  path('XXX/', include('XXX.urls'))

如果你在全局urls.py里写了

from django.urls import include, path

path('home/', include('app01.urls')

然后又在app01里创建了一个urls.py文件,里面有 path('timer',get_timer), 当你请求路径是http://127.0.0.1:8000/timer的时候,会报“找不到页面”,只有请求路径是http://127.0.0.1:8000/home/timer的时候才能够访问到。

这个app01/urls.py文件,照着原本的urls.py文件照写就行。

四、Django路由转发器

我们到目前为止一直用的是 path(‘规则’,视图函数),那有时候我们会发现re_path正则越写越多,越写越复杂,规则也就越来越长。我们的path只是做一个映射,匹配对应上,可是现在相当于把太多规则放在了path部分。如何将path和规则解耦,就是路由转发器帮我们实现的功能。

路由转发器就是Django为我们提供的一个自定义路由的方式。path('路由转换器名称',视图函数)

mysite3/urls.py:

from django.urls import path, re_path
from app01.views import show
from django.urls import register_converter

class MobileConvert(object):
    # 正则规则
    regex = "1[3-9]\d{9}" # 这是手机号规则,1开头。3-9第二个数字,剩下9位随便
    def to_python(self,value):
        return value

register_converter(MobileConvert,"moblie")

urlpatterns = [
    #<规则,传入参数>
    path("index/<moblie:m>",show)
]

对应的视图函数里的show方法:

def show(request,m):
    print(m,type(m))
    return HttpResponse(f"hi,{m}用户") #变量嵌入功能

注意:在Django里,传入到我们视图函数里是以字符串类型传送的。m的类型是str。

由此可见,规则是规则,映射是映射。

五、反向解析

反向解析里涉及重定向redirect和模板语法的标签渲染{%}还没有学到,因此先放一下,后面再回来补。

12.08更新:学完模板啦,我回来补充反向解析啦(也就是我这系列笔记五学完回来补的)。

在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

以上概念不太容易理解,说白了反向解析就是,路由不想写死,也就是解决硬编码问题。如果路由写死,如果更改路由,那就要全局查找这个路由涉及到的代码,比如在其他页面引用了这个路由需要改变其他页面的代码,很麻烦。

写路由线的时候给路由线起个名字,以前都是通过路由去找视图函数,现在是通过路由名字找路由,因此叫反向解析。

 

在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url模板标签   {% url 'url名字' %}
  • 在Python 代码中:使用from django.urls import reverse 函数。

urls.py中为url设置别名参数:

from django.conf.urls import url
from . import views

urlpatterns = [
    #...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]

应用之在模板中反向解析:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<a href="/articles/2012/">2012 Archive</a>

应用之在py文本中反向解析:

from django.shortcuts import redirect
from django.urls import reverse

def redirect_to_year(request):
    year = 2006
    reverse_path=reverse('news-year-archive', args=(year,))
    return redirect(reverse_path)  # 等效 redirect("/articles/2006/")

  

posted on 2023-12-06 14:11  szdbjooo  阅读(81)  评论(0)    收藏  举报