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.
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.
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.
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).
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
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With