【问题标题】:Django templates url - differentiate between same url namesDjango 模板 url - 区分相同的 url 名称
【发布时间】:2021-02-02 21:55:29
【问题描述】:

在我的应用程序中,我有一个名为 download_document 的视图,使用 {% url 'download_document' some_id %} 可以正常工作。

将第 3 方应用安装到虚拟环境中会导致麻烦,因为该应用还有具有相同 urlname 的 download_document 视图(也接受一个 ID 参数)。

如果我想同时使用这个名字,我能以某种方式区分它们吗?例如在同一个模板文件中使用这两种情况?

Python:2.7 姜戈:1.11.16 Debian .


更新 #1:

我的应用名为 infk 。我已经试过了

{% url 'infk:download_document' document.id %}

,但在这种情况下,我得到了 500:u'infk' 不是注册的命名空间。

我还尝试将命名空间添加到顶部 urls.py 文件:

#original
url(r'^infk/', include('infk.urls')),
#modified
url(r'^infk/', include('infk.urls', namespace="infk")),

但在这种情况下,我得到了一个不同的 500: Reverse for 'infk' not found。 'infk' 不是有效的视图函数或模式名称。

要使用第二个,我至少需要将所有反向方法从 ** reverse('infk'...) 更改为 reverse('infk:infk'...) 我真的不想要.

如果我不添加命名空间,有什么方法可以调用我的 download_document 函数? (默认情况下,它会调用 3rd 方应用的 download_document 视图。

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

    前方长篇大论,深呼吸……

    如果我不添加命名空间,有什么方法可以调用我的 download_document 函数? (默认情况下,它调用 3rd 方应用的 download_document 视图。

    这取决于你想要做什么。如果您总是希望您的 download_document 函数在您的整个网站(甚至在 3rd-party-app 提供的页面上)都被调用,您只需将 infk 移动到 urlpatterns 的末尾main_app/urls。看起来像这样:

    main_app/urls.py
    ================================================================================
    from django.conf.urls import include, url
    
    urlpatterns = [
        url(r'^3rd-party-app/', include('3rd-party-app.urls')),
        url(r'^infk/', include('infk.urls')),
    ]
    

    否则,如果您试图在没有命名空间的特定实例中获取您的 download_document,这并不是特别容易。您可以创建一个始终为您的 download_document 函数生成 url 的自定义标签,但这是很多额外的工作,如果您遇到另一个名称冲突,您将不得不一次又一次地这样做,而这只是上面的一步首先对网址进行硬编码。此外,如果您计划将 infk 部署为第三方应用程序,您可能希望使用命名空间来帮助其他人避免遇到与您相同的问题。

    说明

    根据https://docs.djangoproject.com/en/1.11/topics/http/urls/#naming-url-patterns 的文档:

    如果你调用你的 URL 模式 comment 并且另一个应用程序做同样的事情,reverse() 找到的 URL 取决于你项目的 urlpatterns 列表中的最后一个模式。

    因此,如果您更改 main_app/urls.py 文件中包含的 url 的顺序,使 infk 在 3rd-party 应用程序之后,您应该获得 infk download_document。但是,这意味着您总是会得到 infk download_document,这可能会破坏您的第 3 方应用程序中的某些功能。

    示例

    Django 1.x

    来源:https://docs.djangoproject.com/en/1.11/topics/http/urls/#reversing-namespaced-urls

    您修改后的 url(r'^infk/', include('infk.urls', namespace="infk")) 创建了一个实例命名空间,如果您在整个应用程序中使用多个 infk 实例,这可能是有意义的。如果您不是(或者您计划将 infk 部署为第三方应用程序本身),您可能不需要它。无论哪种方式,我都建议您设置应用程序命名空间。

    main_app/urls.py
    ================================================================================
    from django.conf.urls import include, url
    
    urlpatterns = [
    
        # These are both instance namespaces. Note that although the same urls 
        # are being included from infk.urls for both, the final route will be 
        # different.
        url(r'^infk-instance1/', include('infk.urls', namespace='infk-instance1')),
        url(r'^infk-instance2/', include('infk.urls', namespace='infk-instance2')),
    
        # The 3rd-party app your url and reverse functions are colliding with.
        url(r'^3rd-party-app/', include('3rd-party-app.urls')),
    ]
    
    infk/urls.py
    ================================================================================
    from django.conf.urls import url
    from . import views
    
    # This is the application namespace. I recommend setting this regardless of 
    # whether you use instance namespaces.
    app_name = 'infk'
    
    urlpatterns = [
        url(r'^(?P<pk>\d+)/$', views.download_document(), name='download_document'),
    ]
    

    实例命名空间

    实例命名空间会这样调用:

    infk/foo_template.html
    ================================================================================
    ...
      <!-- In this case, {% url 'infk-instance1:download_document' document.id %}
      will return /infk-instance1/<document.id>-->
    
      <a href="{% url 'infk-instance1:download_document' document.id %}">Download Document</a>
    ...
    
    ingk/foo_template.html
    ================================================================================
    ...
      <!-- In this case, {% url 'infk-instance2:download_document' document.id %}
      will return /infk-instance2/<document.id>-->
    
      <a href="{% url 'infk-instance2:download_document' document.id %}">Download Document</a>
    ...
    

    如果需要,您应该仍然可以获取 3rd-party download_document 网址。请注意,为了使其正常工作,必须在 infk.urls 之后包含 3rd-party-app.urls。

    ingk/foo_template.html
    ================================================================================
    ...
      <!-- In this case, {% url 'download_document' document.id %}
      will return /3rd-party-app/<document.id>-->
    
      <a href="{% url 'download_document' document.id %}">Download Document</a>
    ...
    

    应用命名空间

    应用程序命名空间的行为取决于是否为应用程序定义了实例命名空间,以及调用的视图是否定义了 current_app。如果您使用上面定义了应用程序和实例命名空间的示例,那么在 {% url %} 标记中使用应用程序命名空间可能会返回不一致的结果。 (更多信息请参见https://docs.djangoproject.com/en/1.11/topics/http/urls/#reversing-namespaced-urls

    为了便于解释,我假设您没有使用 infk 应用程序的多个实例。您的 main_app/urls.py 可能如下所示:

    main_app/urls.py
    ================================================================================
    from django.conf.urls import include, url
    
    urlpatterns = [
        # No instance namespaces
        url(r'^infk/', include('infk.urls')),
        url(r'^3rd-party-app/', include('3rd-party-app.urls')),
    ]
    

    应用命名空间是这样调用的:

    infk/foo_template.html
    ================================================================================
    ...
      <!-- In this case, {% url 'infk:download_document' document.id %}
      will return /infk/<document.id>-->
    
      <a href="{% url 'infk:download_document' document.id %}">Download Document</a>
    ...
    

    而且,假设在 infk 之后安装了 3rd-party 应用程序,您的 3rd-party 应用程序的 download_document 仍然可以这样调用:

    ingk/foo_template.html
    ================================================================================
    ...
      <!-- In this case, {% url 'download_document' document.id %}
      will return /3rd-party-app/<document.id>-->
    
      <a href="{% url 'download_document' document.id %}">Download Document</a>
    ...
    

    Django >=2.x

    来源:https://docs.djangoproject.com/en/dev/topics/http/urls/#term-application-namespace

    解析器的工作原理与上述基本相同;但是,不要在 urls.py 文件中使用 url(),而是使用 path()re_path()

    【讨论】:

    • 感谢您的简短解释。
    【解决方案2】:

    有一种方法可以避免url 名称冲突。您所要做的就是在url 名称之前添加它们各自的命名空间。根据the docs,您只需要以下内容:

    {% url 'myapp:view-name' %}
    

    通过使用namespaced URL resolution strategy

    【讨论】:

    • 我用您的解决方案更新了 Update #1 下的原始问题,但我无法真正更改项目中所有(几百个)url 类型的出现。我想我需要更改所有模板-> url 标签和所有反向行..
    • @user2194805 我没有看到其他方法可以做到这一点,所以我认为您的 IDE 或编辑器可以很容易地更改所有数百个事件。
    • 好吧,我找到了另一个棘手的解决方法,但是,奇怪的是我无法在 url 模板标签中准确地告诉我想使用哪个。使用相同视图名称的 2 个 3rd 方应用程序很容易发生,恕我直言,能够区分它们非常有用。
    猜你喜欢
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2018-06-02
    • 2018-04-13
    • 2021-11-10
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多