Pablo
Pablo

Reputation: 13580

understading django.shortcuts.reverse, part 2

In Understanding django.shortcuts.redirect I started a thread about reverse and redirect_to.

I still have some problems understanding how reverse works when the first parameter is a string. I read https://docs.djangoproject.com/en/1.4/topics/http/shortcuts/#django.shortcuts.redirect many times and the corresponding part with reverse. But I am still getting a NoReverseMatch exception.

In my ROOT_URLCONF I have

urlpatterns = patterns('',
    url(r'^$', redirect_to, {'url': '/monitor/'}),
    url(r'^monitor/', include('monitor.urls')),
)

In monitor.urls I have

urlpatterns = patterns('monitor.views',
    (r'^$', 'index'),
    (r'^list', 'listall'),
)

and in monitor.urls I've defined code for both functions, index and listall. In listall I added the following lines:

def listall(request):
    <more code goes here>
    print "reversing 1 index: %s " % reverse(index)
    print "reversing 2 index: %s " % reverse('index')
    render_to_response("monitor/list.htmld", params)

If I visit localhost:3000/monitor/list then I can see

reversing 1 index: /monitor/ 

and nothing else, the second reverse raises an exception. Why? What am I missing?

I tracked it down to djangos code django.core.urlresolvers.callable and django.core.urlresolvers.get_mod_func. get_mod_func seems to expect something like "a.b", thats why in callable the very first line returned "index" for func_name but an empty string for mod_name. I changed my second line to

    print "reversing 2 index: %s " % reverse('monitor.views.index')

and it worked as intended. So, why do I need to call reverse with the full module and function name (when I use strings) and the documentation doesn't? What am I missing?

Thanks

Upvotes: 1

Views: 323

Answers (2)

Chris Pratt
Chris Pratt

Reputation: 239360

I'm not sure what part of the documentation you're hung up on, but reverse's first parameter is some identifying method of getting to a view: it can be either a urlpattern name, a full dotted path to the view, or the view itself

So, based on your example, the first method is out because you didn't define a name for your urlpattern. Your first try, reverse(index) worked because you literally passed it the view. Your second try, reverse('index'), doesn't work because it need the full import context, i.e. 'monitor.views.index'. The difference between the two is that when it's a string, Django must interpret that string to create an import for the view -- and 'index' is not enough information to determine the import path.

However, it's far, far better to just name your views if you intend on reversing them, and you should also namespace your included urlpatterns so two different apps don't end up conflicting. So in the project-level urls.py:

urlpatterns = patterns('',
    url(r'^$', redirect_to, {'url': '/monitor/'}),
    url(r'^monitor/', include('monitor.urls', namespace='monitor', app_name='monitor')),
)

Then, in monitor/urls.py:

urlpatterns = patterns('monitor.views',
    (r'^$', 'index', name='index'),
    (r'^list', 'listall', name='listall'),
)

Then, reversing is as simple as reverse('monitor:index').

Upvotes: 2

Vignesh
Vignesh

Reputation: 315

you should be doing something like

reverse('monitor:index')

In ROOT_URLCONF I have

urlpatterns = patterns('',
   (r'^$', redirect_to, {'url': '/monitor/'}),
   (r'^monitor/', include('monitor.urls'),namespace='monitor'),
)

and in monitor.url.py:

urlpatterns = patterns('monitor.views',
   url(r'^$', 'index',name='index'),
)

for more details look at https://docs.djangoproject.com/en/1.4/topics/http/urls/#django.core.urlresolvers.reverse

Upvotes: 2

Related Questions