[Fixed]-Django redirect with kwarg

20👍

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'),
 )

2👍

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']))

0👍

redirect has to redirect to an actual url (it’s an HTTP redirect, not just a Python call).

There is no ‘error_message’ segment in your url conf, even though you have set it up so that by default the view function is called with error_message as a kwarg.

Since this is your index page and you probably don’t want to add extra path segments to the url you could maybe hack it up using GET vars. eg

def page_index(request):
    if 'error_message' in request.GET:
        print request.GET['error_message']

from django.core.urlresolvers import reverse

def add_page(request):
    return redirect('%s?error_message=test' % reverse('page_index'))

urlpatterns = patterns(
    'x.views',
    url(r'^$', 'page_index', name='page_index'),
    url(r'^add/$', 'add_page', name='add_page'),
)

updated:

Thinking about this as I walked home, although your question is about the redirect and kwargs etc, arguably the better option here would be to use Django’s messages framework and leave error_message entirely out of your view kwargs, GET variables etc.

eg

from django.contrib import messages

def add_page(request):
    messages.add_message(request, messages.ERROR, 'test')
    return redirect('page_index')

This also avoids people being able to craft urls with their own made up error messages in them, which could be a security risk.

0👍

You can user django messages. Example:

from django.contrib.auth import messages

messages.info(request, False, "success")
return redirect("app:url")

Then in html, you can use them using custom filter to get messages value based on key, as messages are nothing but dictionary.

{% with messages_dict|get_value_from_dict:'success' as success %}
   {% if sucess %}
         $('#notification_modal').modal('open');
   {% endif %}
{% endwith %}

Custom filter which can be included in templatetags folder under app

from django import template
register = template.Library()


@register.filter('get_value_from_dict')
def get_value_from_dict(dict_data, key):
    """
    usage example {{ your_dict|get_value_from_dict:your_key }}
    """
    if key:
        return dict_data.get(key)
    else:
    return None

Leave a comment