• 第二章:视图层


    一、反向解析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>/,为了让链接正常工作,必须修改对应的herf属性值,于是你去项目里将所有的post/3/都改成entry/3/吗?显然这是不现实的!

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

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

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

    在需要解析URL的地方,对于不同层级,Django提供了不同的工具用于URL反查:

    • 在模板语言中:使用url模板标签。(也就是写前端网页时)
    • 在Python代码中:使用reverse()函数。(也就是写视图函数等情况时)
    • 在更高层的与处理Django模型实例相关的代码中:使用get_absolute_url()方法。(也就是在模型model中)

    范例:

    考虑下面的URLconf:

    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        #...
        path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
        #...
    ]
    

    2019年对应的归档URL是/articles/2019/

    可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    {# Or with the year in a template context variable: #}
    <ul>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    </ul>
    

    在Python代码中,这样使用:

    from django.http import HttpResponseRedirect
    from django.urls import reverse
    
    def redirect_to_year(request):
        # ...
        year = 2019
        # ...
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
    

    其中,起到核心作用的是我们通过name='news-year-archive'为那条url起了一个可以被引用的名称。

    URL名称name使用的字符串可以包含任何你喜欢的字符,但是过度的放纵有可能带来重名的冲突,比如两个不同的app,在各自的urlconf中为某一条url取了相同的name,这就会带来麻烦。为了解决这个问题,又引出了下面的命名空间。

    二、URL命名空间

    URL命名空间可以保证反查到唯一的URL,即使不同的app使用相同的URL名称。

    第三方应用始终使用带命名空间的URL是一个很好的做法。

    类似地,它还允许你在一个应用有多个实例部署的情况下反查URL。 换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。

    实现命名空间的做法很简单,在urlconf文件中添加app_name = 'polls'namespace='author-polls'这种类似的定义。

    范例

    以前面的polls应用的两个实例为例子:'publisher-polls' 和'author-polls'。

    假设我们已经在创建和显示投票时考虑了实例命名空间的问题,代码如下:

    urls.py
    from django.urls import include, path
    
    urlpatterns = [
        path('author-polls/', include('polls.urls', namespace='author-polls')),
        path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
    ]
    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'),
        ...
    ]
    

    如果当前的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'的实例),将使用注册的polls 的最后一个实例。 这将是'publisher-polls',因为它是在urlpatterns中最后一个声明的。

    三、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一个包含嵌套命名空间数据的对象,格式如下:

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

  • 相关阅读:
    oracle连接数
    python——包
    python——软件开发目录规范
    python——模块介绍
    python——二分法
    python——函数的递归调用
    python08——for 循环
    while循环嵌套练习题
    python07——while循环
    python06入门——流程控制之if判断
  • 原文地址:https://www.cnblogs.com/sanduzxcvbnm/p/12834690.html
Copyright © 2020-2023  润新知