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
This commit is contained in:
parent
58ae80b5ea
commit
0fabbf8ce8
|
@ -315,6 +315,25 @@ class TemplateTagNode(Node):
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
return self.mapping.get(self.tagtype, '')
|
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):
|
class WidthRatioNode(Node):
|
||||||
def __init__(self, val_expr, max_expr, max_width):
|
def __init__(self, val_expr, max_expr, max_width):
|
||||||
self.val_expr = val_expr
|
self.val_expr = val_expr
|
||||||
|
@ -868,6 +887,50 @@ def templatetag(parser, token):
|
||||||
return TemplateTagNode(tag)
|
return TemplateTagNode(tag)
|
||||||
templatetag = register.tag(templatetag)
|
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
|
#@register.tag
|
||||||
def widthratio(parser, token):
|
def widthratio(parser, token):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -829,6 +829,40 @@ The argument tells which template bit to output:
|
||||||
|
|
||||||
Note: ``opencomment`` and ``closecomment`` are new in the Django development version.
|
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
|
widthratio
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,17 @@ class Templates(unittest.TestCase):
|
||||||
# Compare to a given parameter
|
# Compare to a given parameter
|
||||||
'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
|
'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'),
|
'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.
|
# Register our custom template loader.
|
||||||
|
|
|
@ -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),
|
||||||
|
)
|
|
@ -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
|
|
@ -7,4 +7,7 @@ urlpatterns = patterns('',
|
||||||
# Always provide the auth system login and logout views
|
# Always provide the auth system login and logout views
|
||||||
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
|
(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
|
||||||
(r'^accounts/logout/$', 'django.contrib.auth.views.login'),
|
(r'^accounts/logout/$', 'django.contrib.auth.views.login'),
|
||||||
|
|
||||||
|
# test urlconf for {% url %} template tag
|
||||||
|
(r'^url_tag/', include('regressiontests.templates.urls')),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue