Django redirect with kwarg
Question: 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?


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

~~Two~~ Three 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 ~~both~~ all 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'),
     )
    

