Django路由层如何获取正确的url

 更新时间:2021年7月15日 14:35  点击:1959

前言

客户端浏览器访问Django后端时通过网关和中间件之后会首先在路由层进行路由匹配,只有路由匹配成功之后才能执行对应的视图函数内的逻辑进行数据的处理,本文就来介绍路由层(以diango1.x版本为例)是如何进行路由匹配的?

Tips - django版本区别

在django1.x版本和django2.x及更高版本之间有些许不同,不同点之一就是路由层的路由表达式,路由表达式之间的不同具体如下述表格:

区别 django1.x django2.x or 3.x
方法 url方法from django.conf.urls import url path方法from django.urls import path
url参数 第一个参数支持正则表达式 第一个参数不支持正则表达式

如果url参数习惯使用正则表达式,2.x和3.x版本的django也提供了另一个方法re_path,该方法就等价于django1.x版本中的path。

# django2.x版本的urls.py
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index',views.index),
    re_path('^index/\d+',views.index),
]

路由匹配

这里我们以django1.x版本进行说明django如何进行路由匹配?django1.x版本中路由与视图的对应关系是通过url方法实现的,而url方法的第一个参数url的正则表达式,只要客户端浏览器访问的url能够和某一个路由成功匹配,就会立刻停止继续匹配之后的路由,直接执行第一个匹配到的视图函数,这样就会产生一个问题,如下述代码:

urlpatterns = [
    url(r'test',views.test),
    url(r'testadd',views.testadd),
]

# 127.0.0.1:8080/testadd 会直接和第一个路由匹配上,永远运行不了下面testadd页面

如何解决上述问题呢?可以指定路由的正则表达式必须以什么开始以什么结尾,并且正则表达式不能为空,否则会匹配所有的url,导致后面的页面无法访问,因此使用正则表达式的url时可以采用下述解决方式:

urlpatterns = [
    # 首页,正则表达式不能写空,否则会匹配所有的url后缀,而导致后面的页面无法访问
    url(r'^$',views.home),
 # ^是指匹配的字符必须以什么开始 $是指匹配的字符必须以什么结尾
    url(r'^test/$',views.test),
    url(r'testadd/',views.testadd),
]

无名分组&有名分组

首先来看什么分组?分组的意思简单来讲就是给某一段正则表达式用小括号括起来。无名分组的意思简单理解就是分组之后的正则表达式没有名字而有名分组就是分组之后正则表达式有名字。~真是深刻的理解。。。

无名分组

无名分组会将分组后括号内的正则表达式匹配到的内容当做位置参数传递给对应的视图函数。

# urls.py
urlpatterns = [
    url(r'test/(\d+)', views.test),   # \d+表示匹配数字
]

# views.py
def test(request, xx):  #  形参xx可以是任意的
    print(xx)
    return HttpResponse('test')

如果在浏览器中访问127.0.0.1:8000/test/100(数字可以是随意的),在pycharm的终端中就会输出100,如果在视图函数test中不增加形参xx就会报错。报错信息如下:

TypeError: test() takes 1 positional argument but 2 were given

    翻译为test函数只有一个形参但是却给了两个实参,因此必须增加一个形参来接收另一个实参。而另一个实参就是无名分组中的正则表达式匹配到的内容。

有名分组

就是给被分组了的正则表达式起一个别名,将括号内正则表达式匹配到的内容当作关键字参数传递给对应的视图函数。

# urls.py
urlpatterns = [
    url(r'test/(?P<id>\d+)',views.test),   # \d+表示匹配数字, id就是分组的正则表达式的名字
]

# views.py
def test(request, id):  # 使用有名分组时,视图函数的形参名字必须与有名分组的名字一致
    print(id)
    return HttpResponse('xx')

如果在浏览器中访问127.0.0.1:8000/test/100(数字可以是随意的),在pycharm的终端中就会输出100,如果在视图函数test中形参名字与有名分组的名字不一致,则会报错,报错信息如下:

TypeError: test() got an unexpected keyword argument 'id'

翻译为test函数得到了一个它不需要的关键字参数id。因此使用有名分组时视图函数的形参必须和有名分组的名字一致。

小提示

有名分组和无名分组不能同时使用,但是每一种分组可以重复使用多次,同时在视图函数中必须有对应数量的形参进行值的接收。

url(r'test/(\d+)/(\d+)/(\d+)',views.test)
url(r'test/(?P<id1>\d+)/(?P<id2>\d+)/(?P<id3>\d+)', views.test)

反向解析

前端浏览器发送过来一条url请求,该url会匹配到一个负责该请求的视图函数(可能同时给视图函数提供一些传参),此为正向匹配。
从视图函数绑定关系的别名出发(可能需要一些参数),寻找一条完整url的过程是反向,所谓解析就是通过别名(或者说是url匹配关系的别名,又或者url-pattern的别名)外加一些参数,获取一条完整的url。

正向匹配: url                 -------------------------------->    视图函数(+参数)
反向解析:别名(参数)  ---------------------------------->   url

使用反向解析的目的就是在前端HTML页面中更加方便的获取一条url,避免硬编码减少程序维护的复杂度。那么如何使用反向解析呢?使用反向解析分为两步:
①在路由匹配文件urls.py中为路由设置别名;
②在视图函数或者在HTML页面中使用别名。

使用反向解析也分为两种情况,一种是路由不涉及分组的情况,另一种就是有名分组和无名分组的反向解析。

路由不涉及分组的反向解析

首先需要在urls.py为路由和视图函数的对应关系设置别名,代码如下:

urlpatterns = [
    re_path('index/', views.index, name='index'),
    re_path('test/', views.test, name='test') # 路由与视图函数的对应关系别名name为test, 可以是任意的,但是必须唯一
] 

设置好路由与视图函数的对应关系的别名之后就可以在后端或者前端HTML页面进行反向解析了,通过别名获取url。

# views.py - 在后端视图函数中反向解析,需要借助模块实现动态解析
from django.shortcuts import render, redirect, HttpResponse, reverse


# Create your views here.
def index(request):
    return HttpResponse('index')


def test(request):
    return redirect(reverse('index'))

上述代码当访问127.0.0.1:8000/test/时就会通过test函数重定向,而重定向的url就是通过reverse方法进行反向解析得到的index/路由。

当然在前端HTML页面上也可以通过模板语法进行反向解析的操作,同样是通过别名找到对应关系解析出url后执行对应的视图函数。

# views.py
from django.shortcuts import render, redirect, HttpResponse


# Create your views here.
def index(request):
    return HttpResponse('index')


def test(request):
    return render(request, 'render_html.html')

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href={% url 'index' %}>click me</a>  <!--通过{% url '别名' %}的语法格式对后端的别名进行解析,点击即可跳转到index/路由-->
</body>
</html>

有名分组&无名分组的反向解析

有名分组和无名分组的反向解析与不分组时有一些不同,有名分组和无名分组反向解析在url.py中的设置和没有分组时的设置操作是一致的,都是通过参数name为路由和视图函数的对应关系起一个别名,但是在存在分组的情况下反向解析时不仅要提供别名还需要路由正则表达式分组中需要的数据,有名分组时反向解析时提供数据的方式不论是在前端还是后端都有两种方式,其中一种是有名分组和无名共有的方式。

首先看无名分组的反向解析:

# urls.py
urlpatterns = [
    re_path('index/(\d+)', views.index, name='index'),
    re_path('test/', views.test, name='test')
]

-----------------------------------------无名分组后端反向解析-------------------------------
# views.py  - 后端的反向解析
def index(request, x):
    return HttpResponse('index')

def test(request):
    # 参数必须是以元组的形式,并且参数必须能够和正则表达式中的分组部分匹配,否则会报错,Reverse for 'func' with no arguments not found. 1 pattern(s) tried: ['index/(\\d+)']
    return redirect(reverse(viewname='index', args=(1,))) 


-----------------------------------------无名分组前端反向解析--------------------------------
# views.py
def index(request, x):
    return HttpResponse('index')

def test(request):
    return render(request, 'render_html.html')

# render_html.html
<body>
<a href={% url 'index' 1 %}>click me</a>   # {% url 别名 分组匹配的参数 %}
</body>

下面再来看有名分组的方向解析,有名分组的反向解析有两种实现方式,第一种与无名分组一致,另一种代码如下:

# urls.py
urlpatterns = [
    re_path('index/(?P<id>\d+)', views.index, name='index'),
    re_path('test/', views.test, name='test')
]

----------------------------------------有名分组反向解析 - 后端反向解析-----------------------
# views.py
def index(request, id):
    return HttpResponse('index')

def test(request):
    # 匹配有名分组的参数是字典的格式字典的key就是有名分组的名字
    return redirect(reverse(viewname='index', kwargs={'id': 2}))

--------------------------------------有名分组反向解析 - 前端反向解析-------------------------
# views.py
def index(request, id):
    return HttpResponse('index')

def test(request):
    return render(request, 'render_html.html')

# render_html.html
<body>
<a href={% url 'index' id=2 %}>click me</a>  # {% url 别名 有名分组名字=分组匹配的参数%} 
</body>

路由分发

django每一个应用都可以有自己的urls.py/templates文件夹/static文件夹,基于这一点django可以非常好的实现分组开发,每个人只写自己负责的应用部分即可,那么又如何将不同的应用整合到一起呢?只需要将所有的应用复制到一个新的django项目中(git协同开发后期再讲...)然后在配置文件中注册所有的应用最后利用路由分发将所有应用整合,**路由分发就是识别当前url属于哪个应用下的,然后直接分发给对应的应用再做进一步的处理。**使用路由分发需要在每个应用下创建urls.py称为子路由,原本的urls.py称为总路由,比如说一个django项目中创建了两个应用分别是first和second,路由分发可以通过如下方式实现:

----------------------------子路由文件---------------------------------------------------
# first应用下的urls.py - first_django/first/urls.py
from django.conf.urls import url
from first import views

urlpatterns = [
    url(r'^index/', views.index),
    url(r'^test/', views.test),
]

# second应用下的urls.py - first_django/second/urls.py
from django.conf.urls import url
from second import views

urlpatterns = [
    url(r'^index/', views.index),
    url(r'^test/', views.test),
]

-----------------------------------------总路由文件--------------------------------------
# first_django/first_django/urls.py
from django.conf.urls import url,include
from django.contrib import admin
from firstp import urls as first_url
from second import urls as second_url

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^first/',include(first_url)),
    url(r'^second/',include(second_url))
]

使用路由分发之后,访问不同的应用下的url路由中必须表示该路由属于哪个应用,比如访问127.0.0.1:8000/first/test,表示先通过first到达总路由进行路由分发然后在first应用中在进行test/部分的匹配。总路由做路由分发时url()的正则表达式参数不能以$结尾,必须以/结尾。

上述总路由文件还有一种简化版的代码,无需导入子路由,直接include子路由字符串,如下:

-----------------------------------------总路由文件--------------------------------------
# first_django/first_django/urls.py
from django.conf.urls import url,include
from django.contrib import admin
# from firstp import urls as first_url
# from second import urls as second_url

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^first/',include('first.urls')),
    url(r'^second/',include('first.urls'))
]

到此这篇关于Django路由层如何获取正确的url的文章就介绍到这了,更多相关Django路由层获取url内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Django def clean()函数对表单中的数据进行验证操作

    这篇文章主要介绍了Django def clean()函数对表单中的数据进行验证操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-09
  • C# 如何解析获取Url参数值

    这篇文章主要介绍了C# 如何解析获取Url参数值,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2020-09-01
  • 使用JavaScript获取URL中的参数(两种方法)

    这篇文章主要介绍了使用JavaScript获取URL中的参数(两种方法)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2016-11-22
  • c#动态改变webservice的url访问地址

    这篇文章主要介绍了c#动态改变webservice的url访问地址,需要的朋友可以参考下...2020-06-25
  • PHP如何使用cURL实现Get和Post请求

    这篇文章主要介绍了PHP如何使用cURL实现Get和Post请求,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-11
  • 在Django中使用MQTT的方法

    这篇文章主要介绍了在Django中使用MQTT的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
  • C# URL短地址压缩算法及短网址原理解析

    这篇文章主要介绍了C# URL短地址压缩算法及短网址原理解析,本文重点给出了算法代码,需要的朋友可以参考下...2020-06-25
  • 解决导入django_filters不成功问题No module named 'django_filter'

    这篇文章主要介绍了解决导入django_filters不成功问题No module named 'django_filter',具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-15
  • node.js如何根据URL返回指定的图片详解

    这篇文章主要介绍了NODE.JS如何根据URL返回指定的图片详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-21
  • 详解如何使用Docker部署Django+MySQL8开发环境

    这篇文章主要介绍了详解如何使用Docker部署Django+MySQL8开发环境,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-07-19
  • js获取url页面id,也就是最后的数字文件名

    这篇文章主要介绍了js获取url页面id,也就是最后的数字文件名,有时候我们需要判断当前页面的id,又不用重新生成页面直接用js获取最后的数字.htm即可...2020-09-25
  • PHP CURL CURLOPT参数说明(curl_setopt)

    CURLOPT_RETURNTRANSFER 选项:curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);如果成功只将结果返回,不自动输出任何内容。如果失败返回FALSEcurl_setopt($ch, CURLOPT_RETURNTRANSFER,0); 或着不使用这个选项:如果成功只...2013-10-04
  • Django 解决由save方法引发的错误

    这篇文章主要介绍了Django 解决由save方法引发的错误,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-21
  • django数据模型中null和blank的区别说明

    这篇文章主要介绍了django数据模型中null和blank的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-03
  • Django表单外键选项初始化的问题及解决方法

    这篇文章主要介绍了Django表单外键选项初始化的问题及解决方法,需本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,要的朋友可以参考下...2021-04-29
  • Django项目连接MongoDB的三种方法

    本文主要介绍了Django项目连接MongoDB的三种方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-27
  • 使用AJAX和Django获取数据的方法实例

    这篇文章主要给大家介绍了关于使用AJAX和Django获取数据的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-25
  • django前端页面下拉选择框默认值设置方式

    这篇文章主要介绍了django前端页面下拉选择框默认值设置方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-10
  • .Net获取URL中文参数值的乱码问题解决方法总结

    这篇文章主要介绍了.Net获取URL中文参数值的乱码问题解决方法,总结分析了针对URL参数传递中出现的乱码问题与相应的解决方法,具有一定参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • django ajax发送post请求的两种方法

    这篇文章主要介绍了django ajax发送post请求的两种方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-04-30