thedk
thedk

Reputation: 1959

Django odd problem with using reverse and url tag

I've found very odd thing about using reverse in Django 1.2.1.

I have:

myapp/
   views.py
   urls.py

in urls.py

from django.conf.urls.defaults import *
urlpatterns = patterns('myapp.views',
 url(r'^$', 'browse'),
)

in views.py

from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse

print reverse('myapp.views.browse')     # <----- this will print correct value  

def browse (request):
    print reverse('myapp.views.browse') # <----- this fails with exception
    return render_to_response('myapp/browse.html')

When I put reverse method anywhere outside the view method (browse - in this case) I get an exception in every further use of reverse or {% url %} tag.

NoReverseMatch at /
Reverse for 'myapp.views.browse' with arguments '()' 
and keyword arguments '{}' not found.

WTF? When I comment/delete the print line outside browse() , second print line inside browse() magically start working!


The most basic case is:

class MyForm(forms.Form):
   field = forms.CharField(default=reverse(....))

def some_view(request):
   print reverse(...)
   ....

1) I define a class in main-scope that is initialized when django initialize (and runs reverse) 2) When a request comes the some_view function has been triggered and it evaluates the reverse function again (and fails with exception).

I don't see anything bad at all in this approach. Why not to initialise some values in the django main-scope with results of the reverse() function ?

Upvotes: 2

Views: 1144

Answers (3)

thedk
thedk

Reputation: 1959

The problem is caused by import hell in python. reverse depends on other things and cannot be used while initialization.

The solution is to use lazy reverse. E.g. using this: http://djangosnippets.org/snippets/499/

Upvotes: 0

Scott
Scott

Reputation: 1477

You will probably need to pass 'request' as the second parameter when calling reverse() from within the view function after it's already been called.

def browse(request):
    print reverse('myapp.views.browse', args=[request])

This is odd behavior indeed, but this might possibly be a solution for now.

Upvotes: 1

airstrike
airstrike

Reputation: 2401

First, you should be naming your URLs in order to use reverse. That is the correct approach AFAIK.

Second, why are you calling reverse from within a FormField? I really don't get it.

Maybe you could enlighten us by posting the full code rather than a curated set of snippets.

# urls.py

url(r'^/$', 'home_view', name='home'),
url(r'^login/$', 'login_view', name='login'),


# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect

def login_view(request):
    # do login stuff and redirect to home
    return HttpResponseRedirect(reverse('home'))

def home(request):
    # do home stuff

    return render_to_response("home.html", locals(), context_instance=RequestContext(request))

Upvotes: 0

Related Questions