Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #2606 -- Added tag for working out the URL of a particular view…

… function.

All work done by Ivan Sagalaev.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@4494 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 0fabbf8ce849dd744d085bae073add038d574e2f 1 parent 58ae80b
@malcolmt malcolmt authored
View
63 django/template/defaulttags.py
@@ -315,6 +315,25 @@ def __init__(self, tagtype):
def render(self, context):
return self.mapping.get(self.tagtype, '')
+class URLNode(Node):
+ def __init__(self, view_name, args, kwargs):
+ self.view_name = view_name
+ self.args = args
+ self.kwargs = kwargs
+
+ def render(self, context):
+ from django.core.urlresolvers import reverse, NoReverseMatch
+ args = [arg.resolve(context) for arg in self.args]
+ kwargs = dict([(k, v.resolve(context)) for k, v in self.kwargs.items()])
+ try:
+ return reverse(self.view_name, args=args, kwargs=kwargs)
+ except NoReverseMatch:
+ try:
+ project_name = settings.SETTINGS_MODULE.split('.')[0]
+ return reverse(project_name + '.' + self.view_name, args=args, kwargs=kwargs)
+ except NoReverseMatch:
+ return ''
+
class WidthRatioNode(Node):
def __init__(self, val_expr, max_expr, max_width):
self.val_expr = val_expr
@@ -868,6 +887,50 @@ def templatetag(parser, token):
return TemplateTagNode(tag)
templatetag = register.tag(templatetag)
+def url(parser, token):
+ """
+ Returns an absolute URL matching given view with its parameters. This is a
+ way to define links that aren't tied to a particular url configuration:
+
+ {% url path.to.some_view arg1,arg2,name1=value1 %}
+
+ The first argument is a path to a view. It can be an absolute python path
+ or just ``app_name.view_name`` without the project name if the view is
+ located inside the project. Other arguments are comma-separated values
+ that will be filled in place of positional and keyword arguments in the
+ URL. All arguments for the URL should be present.
+
+ For example if you have a view ``app_name.client`` taking client's id and
+ the corresponding line in a urlconf looks like this:
+
+ ('^client/(\d+)/$', 'app_name.client')
+
+ and this app's urlconf is included into the project's urlconf under some
+ path:
+
+ ('^clients/', include('project_name.app_name.urls'))
+
+ then in a template you can create a link for a certain client like this:
+
+ {% url app_name.client client.id %}
+
+ The URL will look like ``/clients/client/123/``.
+ """
+ bits = token.contents.split(' ', 2)
+ if len(bits) < 2:
+ raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0]
+ args = []
+ kwargs = {}
+ if len(bits) > 2:
+ for arg in bits[2].split(','):
+ if '=' in arg:
+ k, v = arg.split('=', 1)
+ kwargs[k] = parser.compile_filter(v)
+ else:
+ args.append(parser.compile_filter(arg))
+ return URLNode(bits[1], args, kwargs)
+url = register.tag(url)
+
#@register.tag
def widthratio(parser, token):
"""
View
34 docs/templates.txt
@@ -829,6 +829,40 @@ The argument tells which template bit to output:
Note: ``opencomment`` and ``closecomment`` are new in the Django development version.
+url
+~~~
+
+Returns an absolute URL matching a given view function. This is a way to
+define links that aren't tied to a particular url configuration.
+
+::
+
+ {% url path.to.some_view arg1,arg2,name1=value1 %}
+
+The first argument is a path to a view function. It can be an absolute python
+path or just ``app_name.view_name`` without the project name if the view is
+located inside the project. Other arguments are comma-separated values that
+will be use as positional and keyword arguments in the URL. All arguments
+needed by the URL resolver should be present.
+
+For example, suppose you have a view ``app_name.client`` taking client's id
+and the corresponding line in a urlconf looks like this::
+
+ ('^client/(\d+)/$', 'app_name.client')
+
+If this app's urlconf is included into the project's urlconf under a path
+such as
+
+::
+
+ ('^clients/', include('project_name.app_name.urls'))
+
+then, in a template, you can create a link to this view like this::
+
+ {% url app_name.client client.id %}
+
+The URL rendered in the template will then look like ``/clients/client/123/``.
+
widthratio
~~~~~~~~~~
View
11 tests/regressiontests/templates/tests.py
@@ -645,6 +645,17 @@ def test_templates(self):
# Compare to a given parameter
'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),
+
+ ### URL TAG ########################################################
+ # Successes
+ 'url01' : ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
+ 'url02' : ('{% url regressiontests.templates.views.client_action client.id,action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
+ 'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
+
+ # Failures
+ 'url04' : ('{% url %}', {}, template.TemplateSyntaxError),
+ 'url05' : ('{% url no_such_view %}', {}, ''),
+ 'url06' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
}
# Register our custom template loader.
View
10 tests/regressiontests/templates/urls.py
@@ -0,0 +1,10 @@
+from django.conf.urls.defaults import *
+from regressiontests.templates import views
+
+urlpatterns = patterns('',
+
+ # Test urls for testing reverse lookups
+ (r'^$', views.index),
+ (r'^client/(\d+)/$', views.client),
+ (r'^client/(\d+)/(?P<action>[^/]+)/$', views.client_action),
+)
View
10 tests/regressiontests/templates/views.py
@@ -0,0 +1,10 @@
+# Fake views for testing url reverse lookup
+
+def index(request):
+ pass
+
+def client(request, id):
+ pass
+
+def client_action(request, id, action):
+ pass
View
3  tests/urls.py
@@ -7,4 +7,7 @@
# Always provide the auth system login and logout views
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
(r'^accounts/logout/$', 'django.contrib.auth.views.login'),
+
+ # test urlconf for {% url %} template tag
+ (r'^url_tag/', include('regressiontests.templates.urls')),
)

0 comments on commit 0fabbf8

Please sign in to comment.
Something went wrong with that request. Please try again.