Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django redirect with kwarg

I am new to python and django and i have a question regarding the redirect function.

This is a reduced version of my views.py file.

def page_index(request, error_message=''):
    print error_message

def add_page(request):
    return redirect('page_index') # this work fine
    return redirect('page_index', error_message='test') # this does not work

And here is a short version of my urls.py

urlpatterns = patterns(
    'x.views',
    url(r'^$', 'page_index', {'error_message': 't'}, name='page_index'),
    url(r'^add/$', 'add_page', name='add_page'),
)

When i try redirecting to page_index without the keyword argument everything works fine, but when i use the kwag i get the following error message:

NoReverseMatch at /pages/add/

Reverse for 'page_index' with arguments '()' and keyword arguments '{'error_message': 'test'}' not found.

What am i doing wrong?

like image 438
Justus1 Avatar asked Jan 19 '12 18:01

Justus1


2 Answers

Short answer: There is no place in your url scheme for the 'error_message' keyword.

Longer answer:

The redirect() function is calling reverse() to build a URL; it is going to send the user's browser to that URL by returning an HTTP response with a 302 redirect status code, and the new url. Any keyword arguments that you supply to reverse() are supposed to end up as part of the url -- that's how they get communicated to the user.

In your case, though, the url for 'page_index` is just defined as '^$' -- this is the root url, which looks like 'http://yoursite.com/' in the browser.

If you want to be able to issue a redirect that contains other information, you will need to define a place for it in the url, or add it in a different way.

TwoThree ways are fairly common for this:

  1. Use a query parameter -- this sends the message to the client explicitly; if you aren't careful, people can craft urls to make your index page say whatever they want it to.

    return redirect(reverse('page-index')+"?error_message=test"))
    
  2. Stash the message in the session and pull it out when the next page loads -- this requires that you have sessions configured, and keeps track of everything on the server side, rather than relying on the client to send you back the error message:

    def add_page(request):
        request.session['error_message'] = 'test'
        return redirect('page-index')
    
    def page_index(request):
        print request.session.get('error_message','')
    
  3. Use the messages framework for this -- this is preferred over ad-hoc session attributes, as long as you don't need too many 'types' of message on the same page. If all you have is a space in your template for error message, though, then this is really easy:

    from django.contrib.messages import error
    
    def add_page(request):
        error(request, 'test')
        return redirect('page-index')
    

    And then in your base template, have a block like this somewhere (probably more complex than this; styled, even):

    {% for message in messages %}
        <p>{{ message }}</p>
    {% endfor %}
    

In bothall cases, though, you can remove the arguments from your urls.py -- the message itself is not going to be part of the path component of the URL.

 urlpatterns = patterns(
    'x.views',
     url(r'^$', 'page_index', name='page_index'),
     url(r'^add/$', 'add_page', name='add_page'),
 )
like image 64
Ian Clelland Avatar answered Oct 21 '22 04:10

Ian Clelland


You could either create a named url pattern for each error message, and pass it in the args dict, like this:

url(r'^$', 'page_index', {'error_message': 'test'}, name='test_page_index'),

or if you are willing to put the error message in the actual url you could opt for this:

url(r'(?P"<"error_message">"\w+)/^$', 'page_index', name='page_index'),

(PLEASE REMOVE THE "" around the "<" and ">", had to put them in brackets or they would be excluded form the answer, I guess everything that looks like an html tags is filtered out)

and in the view:

return redirect(reverse('page_index', args=['test']))
like image 2
gregory Avatar answered Oct 21 '22 02:10

gregory