django框架学习:三十.反向解析url和命名空间
前言
反向解析url
在实际的django项目中,经常需要获取某条url,未生成的内容配置url连接。
例如:我在页面上展示一系列文章列表,每个条目都是超级链接,点击就进入该文章的详细页面,路由配置:path('post/<int:pk>/',views.some_view),
在前端中需要为HTML标签<a>标签herf属性提供一个诸如http://www.xxx.com/post/3/的值。其中的域名部门django会自动帮你添加,我们需要关注的是怎么添加/post/3/。
此时一定不能硬编码url为/post/3/,那样费事,不可伸缩,容易出错。试想如果哪天因为某些原因,需要将urlconf中的表达式改成entry/<int:pk>/,为了让链接正常工作,必需修改对应的herf属性值,于是你去项目里将所有的post/3/改为entry/3/吗?显然不合理。
我们需要一种安全可靠,自适应的机制,当修改urlconf中的代码后,无需在项目源码中大范围的搜索,替换失效的硬编码url,为了解决这个问题,django中提供了一种解决方案,只需在url中提供一个name参数,并赋值你自定义的好记的,直观的字符串。通过这个name参数,可以反向解析url,反向url匹配,反向查询或者简单的url反查。
在需要解析url的地方,对于不同层级,django提供了不同工具的用于url反查:
>在模版语言中:使用url模板标签
>在pyhon代码中:使用reverse()函数(0写视图函数等情况时)
>在更高层的预处理django模型实例相关的代码中:使用 get_basolute_url()方法。(也就是在模型model中)
实例:
from django.urls import path
from .import views
2020年对应的归档url是/articles/2019/。
对应的在模板代码中使用下面的模版方法获得他们:
在python代码中,这样使用:
其中起到核心作用的是我们通过name=“news-year-archive”为那条url起了一个可以被引用的名称。
url名称name使用的字符串可以包含任何你喜欢的字符,但是过度放纵有可能重名带来的冲突,比如两个app取了相同的name,为了解决这个问题,又引出了下面的命名空间。
url命名空间
url命名空间可以保证反查到唯一的url,第三方应用始终使用命名空间是一个很好地做法,类似的他还允许你在一个应用有多个实例部署的情况下反查url,换句话讲,因为一个应用的多个实例共享相同的命名url,命名空间提供了一种区分这些命名url的方法。
实现命名空间的做法很简单,在urlconf文件中添加app_name="polls"和namespace="author_polls"类似的定义。
实例:
以上面polls的应用的两个实例为例:"publisher-polls"和"author-polls"。
假设我们已经在创建和显示投票时考虑了实例命名空间的问题,代码如下:
urls.py
app应用urls.py
如果您当前的app实例是其中的一个,例如:我们正在渲染实例“author-polls”中的detail 视图,“polls:index”将解析到“author-polls”实例的index视图。
根据以上设置可以使用一下查询:
在基于类的方法中:
reverse('polls':index,current_app=self.request.resolver_match.namespace)
在模板中:
{% url polls:index" %}
如果没有当前的app实例,例如如果我们在站点其他地方渲染一个页面,"polls:index"将解析到polls注册的最后一个app实例空间,因为没有默认的实例,将使用注册polls的嘴周一个声明。
url命名空间和include的urlconf
可以通过两种方式指定ibclude和urlconf的应用名称空间
第一种
在include的urlconf模块中设置与urlpatterns属性相同级别的app_name属性。必须将实际模块或模块的字符串引用传递到include(),而不是urlpatterns本身的列表。
polls/urls.py:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
]
urls.py:
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
]
此时,polls.urls中定义的URL将具有应用名称空间polls。
第二种
include一个包含嵌套命名空间数据的对象,格式如下:
(<list of path()/re_path() instances>, <application namespace>)
下面是个例子:
from django.urls import include, path
from . import views
polls_patterns = ([
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'), ], 'polls')
urlpatterns = [
path('polls/', include(polls_patterns)),
]
这将include指定的URL模式到给定的app命名空间。
可以使用include()的namespace参数指定app实例命名空间。如果未指定,则app实例命名空间默认为URLconf的app命名空间。