Django视图层:URL的反向解析(主路由include之namespace,子路由之name,{%url%}标签,反向解析示例,URL命名空间

一、视图层The view layer

Django 具有 “视图” 的概念,负责处理用户的请求并返回响应。
在这里插入图片描述

二、URL反向解析Reverse resolution of URLs

在这里插入图片描述
问题:随着功能的增加会出现更多的视图,可能之前配置的正则表达式不够准确,于是就要修改正则表达式,但是正则表达式一旦修改了,之前所有对应的超链接都要修改,真是一件麻烦的事情,而且可能还会漏掉一些超链接忘记修改,有办法让链接根据正则表达式动态生成吗? 动态获取url,就是用反向解析的办法。

Django 提供了一个解决方案,使得URL映射是URL设计唯一的仓库。你使用 URLconf 来填充它,然后可以双向使用它:

  • 从用户/浏览器请求的URL开始,调用对应的Django视图,并从URL中提取参数需要的值。
  • 从相应的Django视图标识(如名称)以及要传递给它的参数来获取相关联的URL 。

第一条我们在前面的章节已经讨论过。第二条就是所谓的反向解析URL,反向 URL匹配,反向URL查找,或简称URL反向

应用范围:①模板中的超链接;②视图中的重定向

使用方法:
①在工程目录下的urls,为include()函数定义namespace属性,namespace=“xxx” 。path(r'^Two/', include('Two.urls',namespace="fan"))
②在app目录下的urls,app_name = "appname",然后为url定义name属性,name =‘xxx’。使用时,在模板中使用url标签,
③在模板里:使用url模板标签{% url namespace:name %}。(也就是写前端网页时)
④在视图中使用reverse()函数,根据正则表达式动态生成地址
⑤在模型model中,get_absolute_url()方法。

跳转方式:
①如果需要带参跳转,如果参数是位置参数,使用args参数
②如果参数是关键字参数,使用kwargs 以字典的形式传送参数
③超链接跳转: <a href = ' {% url ' namespace: name ' %}'></a>
④在视图函数views中跳转:
1, 使用HttpResponseRedirect(‘路径地址’)—>固定获取(地址值固定不变)
2, 使用HttpResponseRedirect( reverse( ‘namespace: name’ ) )方法,动态获取(反向解析)

三、硬编码方式下的情形

在这里插入图片描述

# 工程主目录myproject/urls.py
from django.urls import path, include  # 总路由里才会有include

urlpatterns = [
    path("", include("mysite.urls")),
]
# app目录mysite/urls.py
from django.urls import path
from mysite import views

urlpatterns = [
    path("getblog/", views.get_blog),
    path("sendinfo/", views.send_info),
]
# mysite/views.py
from django.shortcuts import render

def get_blog(request):
    return render(request, "blog1.html")

def send_info(request):
    return render(request, "blog2.html")

# templates/blog1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一篇博客</title>
</head>
<body>
    <p>getblog → views.get_blog → blog1.html测试超链接,跳转成功!</p>
</body>
</html>

# templates/blog2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跳转测试</title>
</head>
<body>
    <a href="/getblog/">sendinfo → views.send_info → blog2.html → getblog测试超链接</a>
</body>
</html>

这里<a href="/getblog/">

  • getblog左右两边都要有 /
  • getblog路由要写对

运行,在url输入sendinfo,跳转到blog2页面,当把鼠标放到页面的链接上时,左下角显示要跳转到getblog
在这里插入图片描述
点击链接,跳转
在这里插入图片描述
小结:这样就可以实现视图的匹配和跳转,这是一种用硬编码连接写的超链接地址(即直接写具体的geblog,这是写死的)。

问题:硬编码方式下,如果一旦更改了根级目录下的url配置路径,就需要改变上述的blog2.html中的模板连接,否则就会出错。有时,一个项目中会有很多的url超链接,改起来很费劲,这个时候就需要上述的url反向解析

四、URL反向解析方式实现

应用范围:①模板中的超链接;②视图中的重定向

使用方法:
①在工程目录下的urls,为include()函数定义namespace属性,namespace=“xxx” 。path(r'^Two/', include('Two.urls',namespace="fan"))
②在app目录下的urls,app_name = "appname",然后为url定义name属性,name =‘xxx’。使用时,在模板中使用url标签,
③在模板里:使用url模板标签{% url namespace:name %}。(也就是写前端网页时)
④在视图中使用reverse()函数,根据正则表达式动态生成地址
⑤在模型model中,get_absolute_url()方法。

# 工程主目录myproject/urls.py
from django.urls import path, include

urlpatterns = [
    path("", include("mysite.urls", namespace="myblog")),
]
# app目录mysite/urls.py
from django.urls import path
from mysite import views

app_name = "mysite"

urlpatterns = [
    path("getblog/", views.get_blog, name="getblog"),
    path("sendinfo/", views.send_info, name="sendinfo"),
]

注意,主路由有namespace,子路由必须声明 app_name = “appname”

mysite/views.py不变
templates/blog1.html不变
templates/blog2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跳转测试</title>
</head>
<body>
    <a href="{% url "myblog:getblog" %}">点我,链接到getblog</a>
</body>
</html>

注意,在前端使用时,格式,{%空格url空格"namespace主路由名:name子路由名"空格%},namespace主路由名:name子路由名用“ ”括起来,它们之间是:冒号,外面href="{% url "myblog:getblog" %}"也有""引号

可实现同样功能,
在这里插入图片描述
小结:如果以后改变了路由地址也不用担心,因为这里用的是namespace和name,只要这两个不变,就可以实现动态路由

五、URL反向解析示例

前言:在反向解析和命名空间之前我们先来说说URLS硬编码,用django 开发应用的时候,可以完全是在urls.py 中硬编码配置地址,在views.py中HttpResponseRedirect()也是硬编码转向地址,当然在template 中也是一样了,这样带来一个问题,如果在urls.py 中修改了某个页面的地址(也就是说更改路由系统中对应的路由分发),那么所有的地方(views.py和template中)都要修改。问题出在硬编码,紧耦合使得在大量的模板中修改 URLs 成为富有挑战性的项目。来看下面的模板文件index.html中,我们到的链接硬编码成这样子:

<li><a href="/goods/index/">url硬编码</a></li>

如果使用软编码之后,无论怎么更改路由系统中的路由分发,只有对应的namespace与name属性值不变,就不必修改在views.py和template中的url,也就是说

<li><a href="{% url "goods:index" %}">url软编码</a></li>

在templates中更改为软编码之后,其实在templates,index.html文件生成的时候,仍然是

<li><a href="/goods/index/">url软编码</a></li>

示例App,目录结构如下,
在这里插入图片描述
1、路由分发:根据路由分发到各个相应的app中,并添加实例命名空间

from django.urls import path, re_path, include
urlpatterns = [
    re_path(r"^goods/", include("mysite_goods.urls", namespace="mysite_goods")),  # 添加实例命名空间
    # re_path(r"^user/", include("mysite_user.urls", namespace="mysite_user")),
    # re_path(r"^order/", include("mysite_order.urls", namespace="mysite_order")),
]

2、子路由,添加应用命名空间。并在url函数中添加name属性。

from django.urls import path, re_path
from mysite_goods import views

app_name = "mysite_goods"  # 注意不能少!

urlpatterns = [
    re_path(r"^index/$", views.index, name="index")
]

3、视图函数

from django.urls import reverse
from django.shortcuts import render

def index(request):
    print(reverse("mysite_goods:index"))  # 利用reverse函数反向解析url
    # 打印结果为/goods/index/
    return render(request, "index.html")

4、静态文件html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>这是index</title>
</head>
<body>
    <a href="/goods/index/">硬链接</a>
    <a href="{% url "mysite_goods:index" %}">软链接</a>
    <!--<a href="/goods/index/">软链接</a>  # 软编码通过解析后得到的结果与硬编码一致-->
</body>
</html>

在这里插入图片描述
在这里插入图片描述
小结:软链接能实现与硬链接相同的URL链接效果。

六、重定向

# 工程主目录myproject/urls.py
from django.urls import path
from mysite import views

urlpatterns = [
    path("", include("mysite.urls", namespace="myblog")),
    path("articles/<int:year>/", views.year_archive, name="news-year-archive"),
]
from django.shortcuts import render

def year_archive(request, year):
    return render(request, "haha.html")
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>重定向测试</title>
</head>
<body>
    <a href="{% url "news-year-archive" 2012 %}">year archive</a>
    <ul>
        {% for yearvar in year_list %}
            <li><a href="{% url "news-year-archive" yearvar %}">{
   
   { yearvar }}archive</a></li>
        {% endfor %}
    </ul>
</body>
</html>

在这里插入图片描述

七.URL命名空间URL namespaces

先看下这个命名空间是干嘛用的?
上面我们解决了url的硬性编码问题,就是给url起个别名,我们知道一个项目可能会包含多个app应用,所以除非你列一个很清晰的表格记录分别给每个app的每个url起了什么别名,以确保他们的名字没有重复,否则我们很难记得是不是已经有了一个叫“张三”的。如果不同app的url起了相同的名字,那就要看谁排在前面了,这种抽奖式方式显然不是我们需要的,为了解决这个问题,就有了命名空间。

URL命名空间可以保证反查到唯一的URL,即使不同的app使用相同的URL名称。URL namespaces allow you to uniquely reverse named URL patterns even if different applications use the same URL names. Similarly, it also allows you to reverse URLs if multiple instances of an application are deployed. In other words, since multiple instances of a single application will share named URLs, namespaces provide a way to tell these named URLs apart. Django applications that make proper use of URL namespacing can be deployed more than once for a particular site. For example django.contrib.admin has an AdminSite class which allows you to deploy more than one instance of the admin.
在这里插入图片描述

命名空间包括两部分,它们都是字符串

七、反向命名空间URLs Reversing namespaced URLs

在这里插入图片描述

最后,URL反向解析:

在实际的Django项目中,经常需要获取某条URL,为生成的内容配置URL链接。

比如,我要在页面上展示一列文章列表,每个条目都是个超级链接,点击就进入该文章的详细页面。

现在我们的urlconf是这么配置的:

path('post/<int:pk>/',views.some_view),

在前端中,这就需要为HTML的<a>标签的href属性提供一个诸如http://www.xxx.com/post/3/的值。其中的域名部分,Django会帮你自动添加无须关心,我们关注的是post/3/

此时,一定不能硬编码URL为post/3/,那样费时、不可伸缩,而且容易出错。试想,如果哪天,因为某种原因,需要将urlconf中的表达式改成entry/<int:pk>/,为了让链接正常工作,必须修改对应的href属性值,于是你去项目里将所有的post/3/都改成entry/3/吗?显然这是不现实的!

我们需要一种安全、可靠、自适应的机制,当修改URLconf中的代码后,无需在项目源码中大范围搜索、替换失效的硬编码URL。

为了解决这个问题,Django提供了一种解决方案,只需在URL中提供一个name参数,并赋值一个你自定义的、好记的、直观的字符串。

通过这个name参数,可以反向解析URL、反向URL匹配、反向URL查询或者简单的URL反查。

source, django, cnblog, bilibili

猜你喜欢

转载自blog.csdn.net/weixin_47008635/article/details/115419382