Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I construct a Django reverse/url using query args?

I have URLs like http://example.com/depict?smiles=CO&width=200&height=200 (and with several other optional arguments)

My urls.py contains:

urlpatterns = patterns('',     (r'^$', 'cansmi.index'),     (r'^cansmi$', 'cansmi.cansmi'),     url(r'^depict$', cyclops.django.depict, name="cyclops-depict"), 

I can go to that URL and get the 200x200 PNG that was constructed, so I know that part works.

In my template from the "cansmi.cansmi" response I want to construct a URL for the named template "cyclops-depict" given some query parameters. I thought I could do

{% url cyclops-depict smiles=input_smiles width=200 height=200 %}

where "input_smiles" is an input to the template via a form submission. In this case it's the string "CO" and I thought it would create a URL like the one at top.

This template fails with a TemplateSyntaxError:

Caught an exception while rendering: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': u'CO', 'height': 200, 'width': 200}' not found.

This is a rather common error message both here on StackOverflow and elsewhere. In every case I found, people were using them with parameters in the URL path regexp, which is not the case I have where the parameters go into the query.

That means I'm doing it wrong. How do I do it right? That is, I want to construct the full URL, including path and query parameters, using something in the template.

For reference,

% python manage.py shell Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)  [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from django.core.urlresolvers import reverse >>> reverse("cyclops-depict", kwargs=dict()) '/depict' >>> reverse("cyclops-depict", kwargs=dict(smiles="CO")) Traceback (most recent call last):   File "<console>", line 1, in <module>   File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 356, in reverse     *args, **kwargs)))   File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 302, in reverse     "arguments '%s' not found." % (lookup_view_s, args, kwargs)) NoReverseMatch: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': 'CO'}' not found. 
like image 428
Andrew Dalke Avatar asked May 06 '10 03:05

Andrew Dalke


People also ask

What does the Django URLs reverse () function do?

the reverse function allows to retrieve url details from url's.py file through the name value provided there. This is the major use of reverse function in Django. The redirect variable is the variable here which will have the reversed value. So the reversed url value will be placed here.

What is reverse and reverse lazy in Django?

Reverse_lazy is, as the name implies, a lazy implementation of the reverse URL resolver. Unlike the traditional reverse function, reverse_lazy won't execute until the value is needed. It is useful because it prevent Reverse Not Found exceptions when working with URLs that may not be immediately known.

How does Django treat a request URL string?

Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL, matching against path_info . Once one of the URL patterns matches, Django imports and calls the given view, which is a Python function (or a class-based view).


2 Answers

Your regular expresion has no place holders (that's why you are getting NoReverseMatch):

url(r'^depict$', cyclops.django.depict, name="cyclops-depict"), 

You could do it like this:

{% url cyclops-depict %}?smiles=CO&width=200&height=200 

URLconf search does not include GET or POST parameters

Or if you wish to use {% url %} tag you should restructure your url pattern to something like

r'^depict/(?P<width>\d+)/(?P<height>\d+)/(?P<smiles>\w+)$'  

then you could do something like

{% url cyclops-depict 200 200 "CO" %} 

Follow-up:

Simple example for custom tag:

from django.core.urlresolvers import reverse from django import template register = template.Library()  @register.tag(name="myurl") def myurl(parser, token):     tokens = token.split_contents()     return MyUrlNode(tokens[1:])  class MyUrlNode(template.Node):     def __init__(self, tokens):         self.tokens = tokens     def render(self, context):         url = reverse('cyclops-depict')         qs = '&'.join([t for t in self.tokens])         return '?'.join((url,qs)) 

You could use this tag in your templates like so:

{% myurl width=200 height=200 name=SomeName %} 

and hopefully it should output something like

/depict?width=200&height=200&name=SomeName 
like image 22
Davor Lucic Avatar answered Sep 18 '22 00:09

Davor Lucic


Building an url with query string by string concatenation as suggested by some answers is as bad idea as building SQL queries by string concatenation. It is complicated, unelegant and especially dangerous with a user provided (untrusted) input. Unfortunately Django does not offer an easy possibility to pass query parameters to the reverse function.

Python standard urllib however provides the desired query string encoding functionality.

In my application I've created a helper function:

def url_with_querystring(path, **kwargs):     return path + '?' + urllib.urlencode(kwargs) # for Python 3, use urllib.parse.urlencode instead 

Then I call it in the view as follows:

quick_add_order_url = url_with_querystring(reverse(order_add),     responsible=employee.id, scheduled_for=datetime.date.today(),     subject='hello world!') # http://localhost/myapp/order/add/?responsible=5& #     scheduled_for=2011-03-17&subject=hello+world%21 

Please note the proper encoding of special characters like space and exclamation mark!

like image 135
geekQ Avatar answered Sep 18 '22 00:09

geekQ