Search code examples
djangodjango-urlsurlconf

Django url patterns having reverse lookup issues with optional parameters


I am having some weird issues with reverse lookups. Here is my url scheme.

url(r'^overview/', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),

When I call return redirect('overview_tutorial', tutorial='tutorial') it isn't loading the tutorial version, it is loading the regular version, which is weird to me. I thought by specifying the name of the url it would use that url but instead it is matching on the first url. Adding a $ to the end of the url scheme solves the problem:

url(r'^overview/$', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),

but I still don't understand why it is doing this. What I really want to do is have a url scheme like this:

url(r'^overview/', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview_tutorial'),
url(r'^overview/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
url(r'^overview/(?P<error>\w+)$', 'ledger.views.overview', name='overview_error')

and then I can redirect to the appropriate appropriate url name and pass in the different parameters. ie:

return redirect('overview_success', success='True')  #or
return redirect('overview_error', error='Login failed. Please try your username/password again')

but those both return as if I just called tutorial view. (which I am now realizing is because a reverse url lookup must build the url and then run it through the url patterns to see where it should direct to).

So then I tried doing this:

url(r'^overview/(?P<tutorial>\w+)$', 'ledger.views.overview', name='overview'),
url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)/(?P<error>\w+)$', 'ledger.views.overview', name='overview_error'),

but when I call return redirect("overview_success", tutorial='', success="Hooray"), I again get an error:

Reverse for 'overview_success' with arguments '()' and keyword arguments '{'success': 'Hooray', 'tutorial': ''}' not found. 1 pattern(s) tried: ['overview/(?P<tutorial>\\w+)/(?P<success>\\w+)$']

Solution

  • It looks like you are trying to use your urlconf to accept messages that you want to send to the user. For example your error message

    return redirect('overview_error', error='Login failed. Please try your username/password again')
    

    However that's not what named groups in the urlconf are for. They are for matching url patterns to determine which view to render. So when you are calling redirect it isn't just sending you to a new url, it's resolving that url based on what you pass it.

    In your second example your redirect call

    return redirect("overview_success", tutorial='', success="Hooray")
    

    is trying to match against your url pattern

    url(r'^overview/(?P<tutorial>\w+)/(?P<success>\w+)$', 'ledger.views.overview', name='overview_success'),
    

    as something like overview//Hooray which as you can see is not a valid pattern because of the empty string passed to tutorial which expects 1 or more "word" characters.

    You can use the messaging framework to send messages to the user. https://docs.djangoproject.com/en/1.7/ref/contrib/messages/#module-django.contrib.messages