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命名空间。

 

上一篇:Django搭建示例项目实战与避坑细节


下一篇:Django 完善项目3