5

How do I use Django's Reverse with an optional parameter for info? I keep on getting

views.py:

def cartForm(request, prod):
    if request.method=="POST":
        quantity = request.POST.get('quantity', False)
        if quantity:
            add_to_cart(request, prod, quantity)
            return HttpResponseRedirect(reverse("cart"))
        #if no quantity indicated, display error message
        return HttpResponseRedirect(reverse('products.views.info', kwargs={'prod': prod, 'error':True}))

def info(request, prod, error=False):
    prod = Product.objects.get(id=prod)
    return render(request, "products/info.html", dict(product = prod, error=error))

urls.py:

url(r'^(?P<prod>\d+)/', "products.views.info", name='info'),

I keep on getting the following error:

Reverse for 'products.views.info' with arguments '()' and keyword arguments '{'prod': u'2', 'error': True}' not found. 1 pattern(s) tried: ['products/(?P<prod>\\d+)/']
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
Aloke Desai
  • 1,029
  • 8
  • 17
  • 27
  • Are you sure your URLs are not duplicated? The match error is showing a pattern different than what your `urls.py` snippet is showing. – Burhan Khalid Jan 14 '14 at 11:53
  • 1
    @BurhanKhalid: Django allows including of url patterns under a partial URL; this pattern is included under `'products/'`. – Martijn Pieters Jan 14 '14 at 11:55
  • possible duplicate of [Django redirect using reverse() to a URL that relies on query strings](http://stackoverflow.com/questions/4477090/django-redirect-using-reverse-to-a-url-that-relies-on-query-strings) – Martijn Pieters Jan 14 '14 at 11:57
  • @MartijnPieters I meant that the pattern is `(?P\d+)` (but then I edited the post because it was actually giving the right error); and then I realized that there are _two_ keywords being passed in when the pattern is only mapped to one; so my question still stands. – Burhan Khalid Jan 14 '14 at 12:17
  • 1
    @BurhanKhalid: And that's the crux of the question here; what does the OP expect the `error` parameter to do here? No other URL pattern is mentioned. – Martijn Pieters Jan 14 '14 at 12:19

4 Answers4

5

You can pass optional GET parameters as:

reverse('products.views.info', kwargs={'prod': prod})+'?error=true&some_other_var=abc'

reverse returns the resolved URL as string, so you can concatenate as many GET parameters as you want.

Aamir Rind
  • 38,793
  • 23
  • 126
  • 164
  • For anyone else using this, here's some code - `return HttpResponseRedirect('%s?%s' % (reverse('url-name', args=(args_in_url_pattern, )), '&'.join(['%s=%s' % (key, value) for key, value in request.GET.items()])))` - should probably additionally be url escaped? – Chris Dec 06 '15 at 13:07
3

Not a direct answer but : why don't you just use the Messages framework (https://docs.djangoproject.com/en/1.6/ref/contrib/messages/).

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
2

Try with optional group in url:

# change (?P<error>\d+) to (?P<error>[a-zA-Z]+) to catch strings in error value
url(r'^(?P<prod>\d+)(?:/(?P<error>\d+))?/', "products.views.info", name='info'),

source: Making a Regex Django URL Token Optional

Community
  • 1
  • 1
ndpu
  • 22,225
  • 6
  • 54
  • 69
0

Adding an argument to the view function doesn't not make it into a URL pattern, in your case you have added the argument directy to the view method, but not mapped it to the URL.

Therefore, when you try to reverse the URL, a pattern that has error is not found, which is why you are getting the error.

You have two options:

  1. Make the pattern optional which I do not recommend.

  2. Map the same view to multiple URLs, with the optional one first as the patterns are matched in the order found:

    url(r'^(?P<prod>\d+)/(?P<error>\d+)/', "products.views.info", name='info-error'),
    url(r'^(?P<prod>\d+)/', "products.views.info", name='info'),
    

Now, in your view:

from django.shortcuts import redirect

def cartForm(request, prod):
    if request.method=="POST":
        quantity = request.POST.get('quantity', False)
        if quantity:
            add_to_cart(request, prod, quantity)
            return HttpResponseRedirect(reverse("cart"))
        #if no quantity indicated, display error message
        return redirect('info-error', prod=foo, error=True)

Here I am using the redirect shortcut

Community
  • 1
  • 1
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284