[Django]-How do you use Django URL namespaces?

3๐Ÿ‘

โœ…

I think that this isnโ€™t possible in django right now. Have a look at this message board post which references Ticket 11559. I think that youโ€™re trying to do the same thing โ€“ effectively pass an implicit parameter to the URL tag.

Also, assuming that sub_urls is from the same app both times you should make sure app_name is the same in both cases. You should only need to change namespace.

๐Ÿ‘คMystic

6๐Ÿ‘

There seems to be no direct way to do it. I would use a similiar solution as you introduced using a template tag, though I found a more generic way. I used the fact that you can pass optional parameters in your url conf, so you can keep track of the namespace:

#urls.py
from django.conf.urls import defaults

urlpatterns = defaults.patterns('',
    defaults.url(r'^foo/', include('sub_urls', namespace='foo', app_name='myapp'), 
    kwargs={'namespace':'foo'}),
    defaults.url(r'^bar/', include('sub_urls', namespace='bar', app_name='myapp'),
    kwargs={'namespace':'bar'}),      
)

That also violates the DRY principle, but not much though ๐Ÿ™‚

Then in your view you get the namespace variable (sub_urls.py would be the same):

#views.py
from django import shortcuts

def myvew(request, namespace):
    context = dict(namespace=namespace)
    return shortcuts.render_to_response('mytemplate.html', context)

Later you just need a simple tag you pass your namespace variable and view name to:

#tags.py
from django import template
from django.core import urlresolvers

register = template.Library()

def namespace_url(namespace, view_name):
   return urlresolvers.reverse('%s:%s' % (namespace, view_name, args=args, kwargs=kwargs)))
register.simple_tag(namespace_url)

and use it in the template (make sure to pass your view name as a string, and not as a template variable):

<!-- mytemplate.html -->
{% load tags %}
{% namespace_url namespace "view1"%}

Thanks for your hint btw.. I was looking for sth. like this.

0๐Ÿ‘

I realize the solution below violates the DRY principal as you have to create essentially duplicate url config files for foo and bar, however I think it should work.

urls.py:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^foo/', include('sub_urls_foo')),
    (r'^bar/', include('sub_urls_bar')),            
)

sub_urls_foo.py:

from django.conf.urls.defaults import patterns, url
from views import view1

urlpatterns = patterns('views',
    url(r'^(?P<view_id>\d+)/$', view1, 'view1_foo', {'namespace': 'view1_foo'})
)

sub_urls_bar.py:

from django.conf.urls.defaults import patterns, url
from views import view1

urlpatterns = patterns('views',
    url(r'^(?P<view_id>\d+)/$', view1, 'view1_bar', {'namespace': 'view1_bar'})
)

views.py:

from django.shortcuts import render_to_response

def view1(request, view_id, namespace):
    return render_to_response('view1.html', locals())

And then for the template use this:

{% url namespace 3 %}

I havenโ€™t tested the idea of using a variable in the name section of the {% url %} tag, but I think it should work.

๐Ÿ‘คSteven Potter

-1๐Ÿ‘

Here is one solution I came up with.

views.py:

from django.shortcuts import render_to_response
from django.template import RequestContext

def render_response_context(view, locals):
    request = locals["request"]
    app = "bar" if request.META["PATH_INFO"].lower().startswith("/bar") else "foo"
    return render_to_response(view, locals, 
        context_instance=RequestContext(request, current_app=app))

def view1(request, view_id):    
    return render_response_context('view1.html', locals())

view1.html:

{% load extras %}
{% namespace_url view1 3 %}

extras.py:

from django import template
from django.core.urlresolvers import reverse

register = template.Library()

@register.tag
def namespace_url(parser, token):
    tag_name, view_string, arg1 = token.split_contents()
    return NamespaceUrlNode(view_string, arg1)

class NamespaceUrlNode(template.Node):
    def __init__(self, view_string, arg1):
        self.view_string = view_string
        self.arg1 = arg1
    def render(self, context):
        return reverse("%s:%s" % (context.current_app, self.view_string), args=[self.arg1])

Basically I made sure to always pass the current_app context as either โ€œfooโ€ or โ€œbarโ€, which I calculate manually by looking at the request URL. Then I use a custom tag that resolves a URL based on current_app.

Itโ€™s not very generic; โ€œfooโ€ and โ€œbarโ€ are hard-coded, and the tag can only take exactly one argument. Even with those issues fixed, this seems like a hack.

๐Ÿ‘คChase Seibert

Leave a comment