skip to Main Content

in my application I’ve got a view called download_document which works fine using {% url ‘download_document’ some_id %} .

Installing a 3rd party app into the virtual environment cause trouble because this app has also the download_document view (also accepting one ID parameter) with the same urlname.

If I’d like to use both with this name, can I somehow make the difference between them? For instance using both cases in the same template file?

Python: 2.7
Django: 1.11.16
Debian .


Update #1:

my app is called infk . I tried already using

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

, but in this case I got a 500 with: u’infk’ is not a registered namespace.

I also tried adding namespace to the top urls.py file:

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

but in this case i got back a different 500: Reverse for ‘infk’ not found. ‘infk’ is not a valid view function or pattern name.

To work the second one I’d need to change at least all reverse methods from ** reverse(‘infk’…) to reverse(‘infk:infk’…) which I don’t really want.

So if I don’t add namespace, is there any way to call my download_document function? (By default it calls the 3rd party app’s download_document view .

2

Answers


  1. There is a way to avoid url name conflicts. All you have to do is to add their respective namespaces before the url name. As per the docs, all you need is the following:

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

    By using the namespaced URL resolution strategy.

    Login or Signup to reply.
  2. Long post ahead, so deep breath…

    So if I don’t add namespace, is there any way to call my download_document function? (By default it calls the 3rd party app’s download_document view .

    That depends on what you’re trying to do. If you always want your download_document function to be called throughout your entire website (even on the pages provided by the 3rd-party-app), you can just move infk to the end of your urlpatterns in main_app/urls. That would look something like this:

    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')),
    ]
    

    Otherwise, if you’re trying to get your download_document in specific instances without namespaces, it’s not particularly easily. You could create a custom tag that always produces the url for your download_document function, but that’s a lot of extra work, and if you run into another name conflict, you’d have to do it again and again, and that’s barely a step above hard-coding the url in the first place. Plus, if you’re planning to deploy infk as a third party app, you’ll probably want to use a namespace to help other people avoid the same problem you’re having.

    Explanation

    According to the docs at https://docs.djangoproject.com/en/1.11/topics/http/urls/#naming-url-patterns:

    If you call your URL pattern comment and another application does the same thing, the URL that reverse() finds depends on whichever pattern is last in your project’s urlpatterns list.

    So if you change the order of your included urls in your main_app/urls.py file such that infk is after the 3rd-party app, you should get the infk download_document. However, this means that you’ll ALWAYS get the infk download_document, which may break some of the functionality in your 3rd-party app.

    Examples

    Django 1.x

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

    Your modified url(r'^infk/', include('infk.urls', namespace="infk")) has created an instance namespace, which might make sense if you are using multiple instances of infk throughout your app. If you aren’t (or you’re planning on deploying infk as a third-party app itself) you probably don’t need that. Either way, I’d recommend you set the application namespace.

    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'),
    ]
    

    Instance Namespaces

    Instance namespaces would be called like this:

    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>
    ...
    

    You should still be able to get the 3rd-party download_document url, if you need it. Note that in order for this to work, 3rd-party-app.urls must be included AFTER infk.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>
    ...
    

    Application Namespaces

    The behavior of application namespaces depends on whether there are instance namespaces defined for the application or not, and whether the view called defines a current_app. If you use the above example where both application and instance namespaces are defined, then using an application namespace in your {% url %} tag may return inconsistent results. (See https://docs.djangoproject.com/en/1.11/topics/http/urls/#reversing-namespaced-urls for more information)

    For ease of explanation, I’m going to assume you are not using multiple instances of the infk app. Your main_app/urls.py might then look like:

    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')),
    ]
    

    Application namespaces are called like this:

    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>
    ...
    

    And, assuming that 3rd-party app is installed AFTER infk, your 3rd-party app’s download_document can still be called like:

    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

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

    The resolver works essentially the same as described above; however, instead of using url() in your urls.py files, use path() or re_path().

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search