Django反向解析和命名空间
一、反向解析URL
在实际的Django项目中,经常需要获取某条URL,为生成的内容配置URL链接。
在之前的Django教程中,URL用的都是硬编码格式,这种格式费时、不可伸缩,而且容易出错。若更改URL则需要将之前所有链接该url都加以修改,工作量太大。所以,需要一种安全、可靠、自适应的机制,当修改URLconf中的代码后,无需在项目源码中大范围搜索、替换URL。
为了解决这个问题,Django提供了一种解决方案,只需在URL中提供一个name参数,并赋值一个自定义的、好理解的、直观的字符串即可。
通过这个name参数,可以反向解析URL、反向URL匹配、反向URL查询或者简单地URL反查。
在需要解析URL的地方,对于不同层级,Django提供了不同的工具用于URL反查:
·在模板语言中:使用url模板标签。
·在视图函数中:使用reverse()函数。
·在Django模型model中:使用get_absolute_url()方法。
示例:
from django.urls import path from . import views urlpatterns = [ path('articles/<int:year>/', views.year_archive, name='news-year-archive'), ]
可以在模板的代码中使用下面的方法获得它:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
在视图函数中,这样使用:
from django.http import HttpResponseRedirect from django.urls import reverse def redirect_to_year(request): ... year = 2019 ... return reverse('news-year-archive', args=(year,))
其中,起到核心作用的是通过name='news-year-archive'为那条url起了一个可以被引用的名称。
URL名称name使用的字符串可以包含任何字符,但是过度的放纵可能带来重名的冲突,比如两个不同的app,在各自的URLconf中为某一条url取了相同的name,这就会带来麻烦。为了解决这个问题,又引出了下面的命名空间。
二、URL命名空间
URL命名空间可以保证反差到唯一的URLconf,即使不同的app使用相同的URL名称。
类似地,它还允许在一个应用有多个实例部署的情况下反查URL。 换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。
实现命名空间的做法很简单,在urlconf文件中添加app_name = 'polls'
这种类似的定义。
例如:
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'), ... ]
根据以上设置,可以使用下面的查询。
在基于视图的方法中:
reverse('polls:index', ....)
在模板中:
{% url 'polls:index' %}
三、URL命名空间和include的URLconf
可以通过两种方式指定include的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一个包含嵌套命名空间数据的对象。
例如:
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命名空间。