• Django 路由分发原理探究


    路由控制之简单配置

    • 看urls.py中的导包from django.urls import path,re_path
      path和re_path区别在于re_path是用正则匹配路由路径,而path就是纯字符串匹配
      所以这里用re_path是为了展示1.0也是有这个功能
      在urls中添加路由列表,第一个参数是url路径中一旦匹配到这个字符串,就会执行views中的函数,
      第一个参数是支持正则写法的,比如以case/case01开头,但不限定结尾

      可以看到只要是以case/case01开头 后面无论添加什么 都返回一样的内容


      为了演示效果,views文件中,导入HttpResponse方法先.

    • 路由正则分组概念
      现在先在views新写一个函数case02,可以看到新增了一个新参,后面会提到

      在urls中我们对路由列表的正则表达式 添加了一个括号(),这个在正则代表分组的意思,这个分组如果配到的话,会连同request一起传给views里的函数,所以必须要有2个形参

      访问结果如下,年份会随着你的url变化而变化,

      然而路由中的分组可以有很多个,注意的一点就是无论是几个分组,都要相应加上request一起传给函数,函数的形参接受数量要一直

    • 路由正则分组规则不严格,导致从上至下解析错误解析的问题
      我们看下面,case02这里我们把前面正则的$结尾限定符号去掉.那么当访问的Url为http://127.0.0.1:8000/case/2088/02/时候会自上而下优先访问case02函数

      本意是要访问case03的,结果因为2条正则规则都符合,自上而下运行,就优先执行了上面一条规则,运行了case02, 要避免这个情况就把$加上去re_path(r"^case/([0-9]{4,})/$",case02),

      分组总结:

    • 如果从URL中获取一个值,那么在周围放置一堆圆括号

    • 根路径后面的第一个路径不需要加反斜杠,比如case是对的/case反而是错误的

    • 每个正则前面建议加上'r' 代表字符串中任何字符都无须转义
      其他的例子,便于理解

    路由控制之有名分组

    • 上面的例子中函数传参是根据位置传的,但是如果我们需求是根据形参名传呢????
      我们需要在urls路由控制参数中用固定的?P<变量名>添加到正则的匹配语法中去,比如([0-9]{4,})就变成了?P<year>([0-9]{4,})
      所以re_path(r"^case/(?P<year>[0-9]{4,})/(?P<mon>[0-9]{2})/$",case03)会传参数request,year= mon=
      我们在case03中故意把年份和月份写反,

      但是输出结果还是正常

    路由控制之分发解耦

    前面的例子中,我们把项目所有的路由分发策略都写在了项目下的urls.py,如果我们有100个app呢,如果每个app下又有100个子页面呢? 我们需要进一步解耦,在项目路由表中按照应用名分发,然后在应用的包中再创建一个urls.py,用于该应用下的路由分发,这样就解耦开来了

    • 第一步需要在项目urls中导入include包 from django.urls import path,re_path,include
    • 第二步在应用下创建urls文件,然后在项目路由中添加分发规则,如果是my_app开头的全部分发到my_app.urls中
      re_path(r"my_app/",include("my_app.urls"))
    • 第三部my_pp中的urls创建规则
      from django.urls import path,re_path
      
      from my_app.views import *
      urlpatterns = [
          re_path(r"^case/(?P<year>[0-9]{4,})/(?P<mon>[0-9]{2})/$",case03),
          path("mytest/",my_test)
      ]
      
    • 访问页面
    • 整个代码页面

    路由控制之登录验证示例

    如前端网页视图,我们平时用get访问是访问网页,但是当我们在输入了账号密码按回车后又是需要递交参数的,

    如果我们get访问的url和<form action="http://127.0.0.1:8000/test/" method="post"> 都是http://127.0.0.1:8000/test/ 要怎么区分这两次访问呢?
    ==注:如果form action 递交数据还是跳回get的url地址,那么前面的ip可以省略 <form action="/test/" method="post">
    在全局的路由分发中urls代码如下

    from my_app.views import *
    urlpatterns = [
        path('test/', beijing_time),
    ]
    

    视图中的views代码如下: 可以看到这个形参request会把请求的方式和内容,并且把提交的信息以字典形式可以轻松获取.

    def beijing_time(request):
        import time
        c = time.time()
        b= time.localtime(c)
        a = time.strftime("%Y-%m-%d %H:%M:%S")
        if request.method=="POST": #这里区分提交方式,如果是POST就开始验证账号密码.
            if request.POST.get("user") == "sxf" and request.POST.get("pwd")=="123":
                return HttpResponse("登陆成功")
            else:
                return HttpResponse("登陆失败")
        elif request.method=="GET":
            return render(request,"test.html",{"data":a})
    

    路由控制之反向解析1

    还是上面的例子,根据路由分发规则,我们get访问的url是http://127.0.0.1:8000/test/,然后POST请求的地址也是http://127.0.0.1:8000/test/
    POST请求的HTML文件和GET请求是同一个HTML文件,但是考虑到后期get的请求地址会变动,那么我们改了get请求的路由规则,比如把test改成login

    from my_app.views import *
    urlpatterns = [
        path('login/', beijing_time),
    ]
    

    但是在我们输入了账号密码递交,却显示404了,因为action的网址还没改,因为把他写死了.

    我们需要用反向解析给路由分发器中取个别名 name="log"

    from my_app.views import *
    urlpatterns = [
        path('login/', beijing_time,name="log"),
    ]
    

    然后HTML文件中用蒙版语法引用这个POST地址,语法为{% url 别名 %}
    <form action="{% url 'log' %}" method="post">
    这样无论前面路由地址怎么更改,都可以获取到路由中的地址路径

    流程控制之反向解析2

    反向解析还有种用法,这种用法是在view函数中根据路由分发器中的name变量

    # 项目的路由分发器代码如下
    urlpatterns = [
        re_path(r"my_app/",include("my_app.urls"))
    ]
    
    

    my_app中的分发路由如下

    urlpatterns = [
        re_path(r"^case3/([0-9]{4,})/([0-9]{2})/$",case03,name = "mytest_reverse3"),  
        # 路径为my_app/case/2019/02/
        path("mytest/2003",my_test,name="mytest_reverse")  
        #路径为my_app/mytest/2003
    ]
    

    views中的函数如下

    def case03(request,mon,year):
        print(reverse("mytest_reverse2",args=(2004,"09",)))
        return HttpResponse("你输入的年份是%s,月份是%s"%(year,mon))
    
    def my_test(request):
    
        print(reverse("mytest_reverse"))
        return HttpResponse("my_test页面")
    
    • 以路径http://127.0.0.1:8000/my_app/mytest/2003为例,会运行my_test函数,会打印输出/my_app/mytest/2003
      reverse("mytest_reverse")会解析出mytest_reverse这个别名的url地址,这里的url是写死的,下面举例一个正则的
    • 以路径my_app/case/2019/02/为例,会运行 case03 函数,别名是mytest_reverse3,那么在case03函数中reverse("mytest_reverse2",args=(2004,"09",))
    • 因为分发路由中的re_parth中有了2个分组,因此我们在reverse函数中要添加2个参数,参数必须符合分组的正则表达规则,打印输出的内容为/my_app/case/2004/09/
    • 这里强调的一点是:函数里的reverse()进行的反向解析和所在哪个函数没有关系 假设我们访问路径为http://127.0.0.1:8000/my_app/mytest/2003

      可以看到我们把2个反向解析都放在一个My_test函数中,他的会因为路径找到my_test这个函数执行,然后reverse反向解析会根据别名解析到下面2个路由分发的规则中
      根据mytest_reverse2别名解析里面的url解析规则,在根据2个分组传入参数2004,09,输出路径/my_app/case/2004/09/
      根据mytest_reverse别名解析里面的url解析规则,解析出固定的路径mytest/2003
    urlpatterns = [
        re_path(r"^case3/([0-9]{4,})/([0-9]{2})/$",case03,name = "mytest_reverse2"),  
        # 路径为my_app/case/2019/02/
        path("mytest/2003",my_test,name="mytest_reverse")  
        #路径为my_app/mytest/2003
    ]
    

    路由控制之名称空间

    我们因为需要反向解析,在应用的分发器中会加入Name参数,以便反向解析动态获取一些数值

    但是反向解析是根据name这个参数来的,不同的应用下name取值可能会重复,就会导致下面这个情况,my_app和my_app2下有相同的函数index,并且他们的命名都是name
    所以my_app下的反向解析会被my_app2的反向解析覆盖,出现了运行各自应用下的index,但是反向解析出现了错误,所以我们需要把命名空间也按照不同的应用进行分隔.

    按照应用分隔命名空间需要2步
    第一:项目总路由那边include里面要添加元祖,参数一是按应用的分发路由,参数二是按应用定义的命名空间
    第二:我们只需要后期reverse函数中使用命名空间:函数名 就可以在反向解析中获取正确的内容了

    看正确的结果

  • 相关阅读:
    使用Python的Mock库进行PySpark单元测试
    库龄报表的相关知识
    使用PlanViz进行ABAP CDS性能分析
    Spark SQL中列转行(UNPIVOT)的两种方法
    Spark中的一些概念
    使用Visual Studio Code进行ABAP开发
    2019年的几个目标
    Dom--样式操作
    Dom选择器--内容文本操作
    Javascript面向
  • 原文地址:https://www.cnblogs.com/Young-shi/p/15068324.html
Copyright © 2020-2023  润新知