Fixed #14389, #9666 -- Started the migration path to make the first argument to url and ssi template tags syntactically consistent with other tags. Thanks to Sean Brant for the draft patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14643 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
591ad8afbf
commit
7ff5580d95
|
@ -1,7 +1,8 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_modify adminmedia %}
|
{% load i18n admin_modify adminmedia %}
|
||||||
|
{% load url from future %}
|
||||||
{% block extrahead %}{{ block.super }}
|
{% block extrahead %}{{ block.super }}
|
||||||
{% url admin:jsi18n as jsi18nurl %}
|
{% url 'admin:jsi18n' as jsi18nurl %}
|
||||||
<script type="text/javascript" src="{{ jsi18nurl|default:"../../../../jsi18n/" }}"></script>
|
<script type="text/javascript" src="{{ jsi18nurl|default:"../../../../jsi18n/" }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
|
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
{% load url from future %}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE|default:"en-us" }}" xml:lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE|default:"en-us" }}" xml:lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
|
||||||
<head>
|
<head>
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
@ -28,18 +28,18 @@
|
||||||
{% trans 'Welcome,' %}
|
{% trans 'Welcome,' %}
|
||||||
<strong>{% filter force_escape %}{% firstof user.first_name user.username %}{% endfilter %}</strong>.
|
<strong>{% filter force_escape %}{% firstof user.first_name user.username %}{% endfilter %}</strong>.
|
||||||
{% block userlinks %}
|
{% block userlinks %}
|
||||||
{% url django-admindocs-docroot as docsroot %}
|
{% url 'django-admindocs-docroot' as docsroot %}
|
||||||
{% if docsroot %}
|
{% if docsroot %}
|
||||||
<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
|
<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% url admin:password_change as password_change_url %}
|
{% url 'admin:password_change' as password_change_url %}
|
||||||
{% if password_change_url %}
|
{% if password_change_url %}
|
||||||
<a href="{{ password_change_url }}">
|
<a href="{{ password_change_url }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ root_path }}password_change/">
|
<a href="{{ root_path }}password_change/">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% trans 'Change password' %}</a> /
|
{% trans 'Change password' %}</a> /
|
||||||
{% url admin:logout as logout_url %}
|
{% url 'admin:logout' as logout_url %}
|
||||||
{% if logout_url %}
|
{% if logout_url %}
|
||||||
<a href="{{ logout_url }}">
|
<a href="{{ logout_url }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load adminmedia admin_list i18n %}
|
{% load adminmedia admin_list i18n %}
|
||||||
|
{% load url from future %}
|
||||||
{% block extrastyle %}
|
{% block extrastyle %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
|
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />
|
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if cl.formset or action_form %}
|
{% if cl.formset or action_form %}
|
||||||
{% url admin:jsi18n as jsi18nurl %}
|
{% url 'admin:jsi18n' as jsi18nurl %}
|
||||||
<script type="text/javascript" src="{{ jsi18nurl|default:'../../jsi18n/' }}"></script>
|
<script type="text/javascript" src="{{ jsi18nurl|default:'../../jsi18n/' }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ media.css }}
|
{{ media.css }}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block userlinks %}{% url django-admindocs-docroot as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
{% load url from future %}
|
||||||
|
{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
||||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %}
|
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %}
|
||||||
|
|
||||||
{% block title %}{% trans 'Password change successful' %}{% endblock %}
|
{% block title %}{% trans 'Password change successful' %}{% endblock %}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n adminmedia %}
|
{% load i18n adminmedia %}
|
||||||
|
{% load url from future %}
|
||||||
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
|
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
|
||||||
{% block userlinks %}{% url django-admindocs-docroot as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
||||||
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %}
|
{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %}
|
||||||
|
|
||||||
{% block title %}{% trans 'Password change' %}{% endblock %}
|
{% block title %}{% trans 'Password change' %}{% endblock %}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{% load i18n %}{% autoescape off %}
|
{% load i18n %}{% load url from future %}{% autoescape off %}
|
||||||
{% trans "You're receiving this e-mail because you requested a password reset" %}
|
{% trans "You're receiving this e-mail because you requested a password reset" %}
|
||||||
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
|
{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
|
||||||
|
|
||||||
{% trans "Please go to the following page and choose a new password:" %}
|
{% trans "Please go to the following page and choose a new password:" %}
|
||||||
{% block reset_link %}
|
{% block reset_link %}
|
||||||
{{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb36=uid token=token %}
|
{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
|
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
|
||||||
|
|
||||||
|
|
|
@ -290,24 +290,30 @@ def include_is_allowed(filepath):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class SsiNode(Node):
|
class SsiNode(Node):
|
||||||
def __init__(self, filepath, parsed):
|
def __init__(self, filepath, parsed, legacy_filepath=True):
|
||||||
self.filepath, self.parsed = filepath, parsed
|
self.filepath = filepath
|
||||||
|
self.parsed = parsed
|
||||||
|
self.legacy_filepath = legacy_filepath
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
if not include_is_allowed(self.filepath):
|
filepath = self.filepath
|
||||||
|
if not self.legacy_filepath:
|
||||||
|
filepath = filepath.resolve(context)
|
||||||
|
|
||||||
|
if not include_is_allowed(filepath):
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
return "[Didn't have permission to include file]"
|
return "[Didn't have permission to include file]"
|
||||||
else:
|
else:
|
||||||
return '' # Fail silently for invalid includes.
|
return '' # Fail silently for invalid includes.
|
||||||
try:
|
try:
|
||||||
fp = open(self.filepath, 'r')
|
fp = open(filepath, 'r')
|
||||||
output = fp.read()
|
output = fp.read()
|
||||||
fp.close()
|
fp.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
output = ''
|
output = ''
|
||||||
if self.parsed:
|
if self.parsed:
|
||||||
try:
|
try:
|
||||||
t = Template(output, name=self.filepath)
|
t = Template(output, name=filepath)
|
||||||
return t.render(context)
|
return t.render(context)
|
||||||
except TemplateSyntaxError, e:
|
except TemplateSyntaxError, e:
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
@ -356,8 +362,9 @@ class TemplateTagNode(Node):
|
||||||
return self.mapping.get(self.tagtype, '')
|
return self.mapping.get(self.tagtype, '')
|
||||||
|
|
||||||
class URLNode(Node):
|
class URLNode(Node):
|
||||||
def __init__(self, view_name, args, kwargs, asvar):
|
def __init__(self, view_name, args, kwargs, asvar, legacy_view_name=True):
|
||||||
self.view_name = view_name
|
self.view_name = view_name
|
||||||
|
self.legacy_view_name = legacy_view_name
|
||||||
self.args = args
|
self.args = args
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.asvar = asvar
|
self.asvar = asvar
|
||||||
|
@ -365,22 +372,27 @@ class URLNode(Node):
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
args = [arg.resolve(context) for arg in self.args]
|
args = [arg.resolve(context) for arg in self.args]
|
||||||
kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
|
kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context))
|
||||||
for k, v in self.kwargs.items()])
|
for k, v in self.kwargs.items()])
|
||||||
|
|
||||||
|
view_name = self.view_name
|
||||||
|
if not self.legacy_view_name:
|
||||||
|
view_name = view_name.resolve(context)
|
||||||
|
|
||||||
# Try to look up the URL twice: once given the view name, and again
|
# Try to look up the URL twice: once given the view name, and again
|
||||||
# relative to what we guess is the "main" app. If they both fail,
|
# relative to what we guess is the "main" app. If they both fail,
|
||||||
# re-raise the NoReverseMatch unless we're using the
|
# re-raise the NoReverseMatch unless we're using the
|
||||||
# {% url ... as var %} construct in which cause return nothing.
|
# {% url ... as var %} construct in which cause return nothing.
|
||||||
url = ''
|
url = ''
|
||||||
try:
|
try:
|
||||||
url = reverse(self.view_name, args=args, kwargs=kwargs, current_app=context.current_app)
|
url = reverse(view_name, args=args, kwargs=kwargs, current_app=context.current_app)
|
||||||
except NoReverseMatch, e:
|
except NoReverseMatch, e:
|
||||||
if settings.SETTINGS_MODULE:
|
if settings.SETTINGS_MODULE:
|
||||||
project_name = settings.SETTINGS_MODULE.split('.')[0]
|
project_name = settings.SETTINGS_MODULE.split('.')[0]
|
||||||
try:
|
try:
|
||||||
url = reverse(project_name + '.' + self.view_name,
|
url = reverse(project_name + '.' + view_name,
|
||||||
args=args, kwargs=kwargs, current_app=context.current_app)
|
args=args, kwargs=kwargs,
|
||||||
|
current_app=context.current_app)
|
||||||
except NoReverseMatch:
|
except NoReverseMatch:
|
||||||
if self.asvar is None:
|
if self.asvar is None:
|
||||||
# Re-raise the original exception, not the one with
|
# Re-raise the original exception, not the one with
|
||||||
|
@ -922,6 +934,11 @@ def ssi(parser, token):
|
||||||
|
|
||||||
{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
|
{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.warn('The syntax for the ssi template tag is changing. Load the `ssi` tag from the `future` tag library to start using the new behavior.',
|
||||||
|
category=PendingDeprecationWarning)
|
||||||
|
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
parsed = False
|
parsed = False
|
||||||
if len(bits) not in (2, 3):
|
if len(bits) not in (2, 3):
|
||||||
|
@ -933,7 +950,7 @@ def ssi(parser, token):
|
||||||
else:
|
else:
|
||||||
raise TemplateSyntaxError("Second (optional) argument to %s tag"
|
raise TemplateSyntaxError("Second (optional) argument to %s tag"
|
||||||
" must be 'parsed'" % bits[0])
|
" must be 'parsed'" % bits[0])
|
||||||
return SsiNode(bits[1], parsed)
|
return SsiNode(bits[1], parsed, legacy_filepath=True)
|
||||||
ssi = register.tag(ssi)
|
ssi = register.tag(ssi)
|
||||||
|
|
||||||
#@register.tag
|
#@register.tag
|
||||||
|
@ -945,8 +962,36 @@ def load(parser, token):
|
||||||
``django/templatetags/news/photos.py``::
|
``django/templatetags/news/photos.py``::
|
||||||
|
|
||||||
{% load news.photos %}
|
{% load news.photos %}
|
||||||
|
|
||||||
|
Can also be used to load an individual tag/filter from
|
||||||
|
a library::
|
||||||
|
|
||||||
|
{% load byline from news %}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
|
if len(bits) >= 4 and bits[-2] == "from":
|
||||||
|
try:
|
||||||
|
taglib = bits[-1]
|
||||||
|
lib = get_library(taglib)
|
||||||
|
except InvalidTemplateLibrary, e:
|
||||||
|
raise TemplateSyntaxError("'%s' is not a valid tag library: %s" %
|
||||||
|
(taglib, e))
|
||||||
|
else:
|
||||||
|
temp_lib = Library()
|
||||||
|
for name in bits[1:-2]:
|
||||||
|
if name in lib.tags:
|
||||||
|
temp_lib.tags[name] = lib.tags[name]
|
||||||
|
# a name could be a tag *and* a filter, so check for both
|
||||||
|
if name in lib.filters:
|
||||||
|
temp_lib.filters[name] = lib.filters[name]
|
||||||
|
elif name in lib.filters:
|
||||||
|
temp_lib.filters[name] = lib.filters[name]
|
||||||
|
else:
|
||||||
|
raise TemplateSyntaxError("'%s' is not a valid tag or filter in tag library '%s'" %
|
||||||
|
(name, taglib))
|
||||||
|
parser.add_library(temp_lib)
|
||||||
|
else:
|
||||||
for taglib in bits[1:]:
|
for taglib in bits[1:]:
|
||||||
# add the library to the parser
|
# add the library to the parser
|
||||||
try:
|
try:
|
||||||
|
@ -1140,6 +1185,11 @@ def url(parser, token):
|
||||||
|
|
||||||
The URL will look like ``/clients/client/123/``.
|
The URL will look like ``/clients/client/123/``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.warn('The syntax for the url template tag is changing. Load the `url` tag from the `future` tag library to start using the new behavior.',
|
||||||
|
category=PendingDeprecationWarning)
|
||||||
|
|
||||||
bits = token.split_contents()
|
bits = token.split_contents()
|
||||||
if len(bits) < 2:
|
if len(bits) < 2:
|
||||||
raise TemplateSyntaxError("'%s' takes at least one argument"
|
raise TemplateSyntaxError("'%s' takes at least one argument"
|
||||||
|
@ -1196,7 +1246,7 @@ def url(parser, token):
|
||||||
else:
|
else:
|
||||||
args.append(parser.compile_filter(value))
|
args.append(parser.compile_filter(value))
|
||||||
|
|
||||||
return URLNode(viewname, args, kwargs, asvar)
|
return URLNode(viewname, args, kwargs, asvar, legacy_view_name=True)
|
||||||
url = register.tag(url)
|
url = register.tag(url)
|
||||||
|
|
||||||
#@register.tag
|
#@register.tag
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import Library, Node, Template, TemplateSyntaxError
|
||||||
|
from django.template.defaulttags import kwarg_re, include_is_allowed, SsiNode, URLNode
|
||||||
|
from django.utils.encoding import smart_str
|
||||||
|
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def ssi(parser, token):
|
||||||
|
"""
|
||||||
|
Outputs the contents of a given file into the page.
|
||||||
|
|
||||||
|
Like a simple "include" tag, the ``ssi`` tag includes the contents
|
||||||
|
of another file -- which must be specified using an absolute path --
|
||||||
|
in the current page::
|
||||||
|
|
||||||
|
{% ssi "/home/html/ljworld.com/includes/right_generic.html" %}
|
||||||
|
|
||||||
|
If the optional "parsed" parameter is given, the contents of the included
|
||||||
|
file are evaluated as template code, with the current context::
|
||||||
|
|
||||||
|
{% ssi "/home/html/ljworld.com/includes/right_generic.html" parsed %}
|
||||||
|
"""
|
||||||
|
bits = token.contents.split()
|
||||||
|
parsed = False
|
||||||
|
if len(bits) not in (2, 3):
|
||||||
|
raise TemplateSyntaxError("'ssi' tag takes one argument: the path to"
|
||||||
|
" the file to be included")
|
||||||
|
if len(bits) == 3:
|
||||||
|
if bits[2] == 'parsed':
|
||||||
|
parsed = True
|
||||||
|
else:
|
||||||
|
raise TemplateSyntaxError("Second (optional) argument to %s tag"
|
||||||
|
" must be 'parsed'" % bits[0])
|
||||||
|
filepath = parser.compile_filter(bits[1])
|
||||||
|
return SsiNode(filepath, parsed, legacy_filepath=False)
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
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 %}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
{% url "path.to.some_view" name1=value1 name2=value2 %}
|
||||||
|
|
||||||
|
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.split_contents()
|
||||||
|
if len(bits) < 2:
|
||||||
|
raise TemplateSyntaxError("'%s' takes at least one argument"
|
||||||
|
" (path to a view)" % bits[0])
|
||||||
|
viewname = parser.compile_filter(bits[1])
|
||||||
|
args = []
|
||||||
|
kwargs = {}
|
||||||
|
asvar = None
|
||||||
|
bits = bits[2:]
|
||||||
|
if len(bits) >= 2 and bits[-2] == 'as':
|
||||||
|
asvar = bits[-1]
|
||||||
|
bits = bits[:-2]
|
||||||
|
|
||||||
|
if len(bits):
|
||||||
|
for bit in bits:
|
||||||
|
match = kwarg_re.match(bit)
|
||||||
|
if not match:
|
||||||
|
raise TemplateSyntaxError("Malformed arguments to url tag")
|
||||||
|
name, value = match.groups()
|
||||||
|
if name:
|
||||||
|
kwargs[name] = parser.compile_filter(value)
|
||||||
|
else:
|
||||||
|
args.append(parser.compile_filter(value))
|
||||||
|
|
||||||
|
return URLNode(viewname, args, kwargs, asvar, legacy_view_name=False)
|
|
@ -131,6 +131,11 @@ their deprecation, as per the :ref:`Django deprecation policy
|
||||||
been deprecated in favor of the
|
been deprecated in favor of the
|
||||||
:class:`~django.contrib.staticfiles.handlers.StaticFilesHandler`.
|
:class:`~django.contrib.staticfiles.handlers.StaticFilesHandler`.
|
||||||
|
|
||||||
|
* The :ttag:`url` and :ttag:`ssi` template tags will be
|
||||||
|
modified so that the first argument to each tag is a
|
||||||
|
template variable, not an implied string. The new-style
|
||||||
|
behavior is provided in the ``future`` template tag library.
|
||||||
|
|
||||||
* 2.0
|
* 2.0
|
||||||
* ``django.views.defaults.shortcut()``. This function has been moved
|
* ``django.views.defaults.shortcut()``. This function has been moved
|
||||||
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
|
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
|
||||||
|
|
|
@ -657,6 +657,17 @@ load
|
||||||
|
|
||||||
Load a custom template tag set.
|
Load a custom template tag set.
|
||||||
|
|
||||||
|
For example, the following template would load all the tags and filters registered
|
||||||
|
in ``somelibrary`` and ``otherlibrary``::
|
||||||
|
|
||||||
|
{% load somelibrary otherlibrary %}
|
||||||
|
|
||||||
|
You can also selectively load individual templates or tags from a library, using
|
||||||
|
the ``from`` argument. In this example, the template tags/filters named ``foo``
|
||||||
|
and ``bar`` will be loaded from ``somelibrary``::
|
||||||
|
|
||||||
|
{% load foo bar from somelibrary %}
|
||||||
|
|
||||||
See :doc:`Custom tag and filter libraries </howto/custom-template-tags>` for more information.
|
See :doc:`Custom tag and filter libraries </howto/custom-template-tags>` for more information.
|
||||||
|
|
||||||
.. templatetag:: now
|
.. templatetag:: now
|
||||||
|
@ -838,6 +849,30 @@ Note that if you use ``{% ssi %}``, you'll need to define
|
||||||
|
|
||||||
See also: ``{% include %}``.
|
See also: ``{% include %}``.
|
||||||
|
|
||||||
|
.. admonition:: Forwards compatibility
|
||||||
|
|
||||||
|
.. versionchanged:: 1.3
|
||||||
|
|
||||||
|
In Django 1.5, the behavior of the :ttag:`ssi` template tag will
|
||||||
|
change, with the the first argument being made into a context
|
||||||
|
variable, rather than being a special case unquoted constant. This
|
||||||
|
will allow the :ttag:`ssi` tag to use a context variable as the
|
||||||
|
value of the page to be included.
|
||||||
|
|
||||||
|
In order to provide a forwards compatibility path, Django 1.3
|
||||||
|
provides a future compatibility library -- ``future`` -- that
|
||||||
|
implements the new behavior. To use this library, add a
|
||||||
|
:ttag:`load` call at the top of any template using the :ttag:`ssi`
|
||||||
|
tag, and wrap the first argument to the :ttag:`ssi` tag in quotes.
|
||||||
|
For example::
|
||||||
|
|
||||||
|
{% load ssi from future %}
|
||||||
|
{% ssi '/home/html/ljworld.com/includes/right_generic.html' %}
|
||||||
|
|
||||||
|
In Django 1.5, the unquoted constant behavior will be replaced
|
||||||
|
with the behavior provided by the ``future`` tag library.
|
||||||
|
Existing templates be migrated to use the new syntax.
|
||||||
|
|
||||||
.. templatetag:: templatetag
|
.. templatetag:: templatetag
|
||||||
|
|
||||||
templatetag
|
templatetag
|
||||||
|
@ -955,10 +990,37 @@ here's what it looks like::
|
||||||
{% url path.to.view arg,arg2 %}
|
{% url path.to.view arg,arg2 %}
|
||||||
{% url path.to.view arg, arg2 %}
|
{% url path.to.view arg, arg2 %}
|
||||||
|
|
||||||
This syntax doesn't support the use of literal commas, or or equals
|
This syntax doesn't support the use of literal commas, or equals
|
||||||
signs. Did we mention you shouldn't use this syntax in any new
|
signs. Did we mention you shouldn't use this syntax in any new
|
||||||
projects?
|
projects?
|
||||||
|
|
||||||
|
.. admonition:: Forwards compatibility
|
||||||
|
|
||||||
|
.. versionchanged:: 1.3
|
||||||
|
|
||||||
|
In Django 1.5, the behavior of the :ttag:`url` template tag will
|
||||||
|
change, with the the first argument being made into a context
|
||||||
|
variable, rather than being a special case unquoted constant. This
|
||||||
|
will allow the :ttag:`url` tag to use a context variable as the
|
||||||
|
value of the URL name to be reversed.
|
||||||
|
|
||||||
|
In order to provide a forwards compatibility path, Django 1.3
|
||||||
|
provides a future compatibility library -- ``future`` -- that
|
||||||
|
implements the new behavior. To use this library, add a
|
||||||
|
:ttag:`load` call at the top of any template using the :ttag:`url`
|
||||||
|
tag, and wrap the first argument to the :ttag:`url` tag in quotes.
|
||||||
|
For example::
|
||||||
|
|
||||||
|
{% load url from future %}
|
||||||
|
{% url 'myapp:view-name' %}
|
||||||
|
|
||||||
|
The new library also drops support for the comma syntax for
|
||||||
|
separating arguments to the :ttag:`url` template tag.
|
||||||
|
|
||||||
|
In Django 1.5, the old behavior will be replaced with the behavior
|
||||||
|
provided by the ``future`` tag library. Existing templates be
|
||||||
|
migrated to use the new syntax.
|
||||||
|
|
||||||
.. templatetag:: widthratio
|
.. templatetag:: widthratio
|
||||||
|
|
||||||
widthratio
|
widthratio
|
||||||
|
|
|
@ -344,3 +344,44 @@ and Ctrl-C test termination) have been made redundant. In view of this
|
||||||
redundancy, :class:`~django.test.simple.DjangoTestRunner` has been
|
redundancy, :class:`~django.test.simple.DjangoTestRunner` has been
|
||||||
turned into an empty placeholder class, and will be removed entirely
|
turned into an empty placeholder class, and will be removed entirely
|
||||||
in Django 1.5.
|
in Django 1.5.
|
||||||
|
|
||||||
|
Changes to :ttag:`url` and :ttag:`ssi`
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Most template tags will allow you to pass in either constants or
|
||||||
|
variables as arguments -- for example::
|
||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
allows you to specify a base template as a constant, but if you have a
|
||||||
|
context variable ``templ`` that contains the value ``base.html``::
|
||||||
|
|
||||||
|
{% extends templ %}
|
||||||
|
|
||||||
|
is also legal.
|
||||||
|
|
||||||
|
However, due to an accident of history, the :ttag:`url` and
|
||||||
|
:ttag:`ssi` are different. These tags use the second, quoteless
|
||||||
|
syntax, but interpret the argument as a constant. This means it isn't
|
||||||
|
possible to use a context variable as the target of a :ttag:`url` and
|
||||||
|
:ttag:`ssi` tag.
|
||||||
|
|
||||||
|
Django 1.3 marks the start of the process to correct this historical
|
||||||
|
accident. Django 1.3 adds a new template library -- ``future`` -- that
|
||||||
|
provides alternate implementations of the :ttag:`url` and :ttag:`ssi`
|
||||||
|
template tags. This ``future`` library implement behavior that makes
|
||||||
|
the handling of the first argument consistent with the handling of all
|
||||||
|
other variables. So, an existing template that contains::
|
||||||
|
|
||||||
|
{% url sample %}
|
||||||
|
|
||||||
|
should be replaced with::
|
||||||
|
|
||||||
|
{% load url from future %}
|
||||||
|
{% url 'sample' %}
|
||||||
|
|
||||||
|
The tags implementing the old behavior have been deprecated, and in
|
||||||
|
Django 1.5, the old behavior will be replaced with the new behavior.
|
||||||
|
To ensure compatibility with future versions of Django, existing
|
||||||
|
templates should be modified to use the new ``future`` libraries and
|
||||||
|
syntax.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
unicode: {{ user }}
|
{% load url from future %}unicode: {{ user }}
|
||||||
id: {{ user.id }}
|
id: {{ user.id }}
|
||||||
username: {{ user.username }}
|
username: {{ user.username }}
|
||||||
url: {% url userpage user %}
|
url: {% url 'userpage' user %}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
This is for testing an ssi include. {{ test }}
|
|
@ -51,7 +51,12 @@ class EchoNode(template.Node):
|
||||||
def do_echo(parser, token):
|
def do_echo(parser, token):
|
||||||
return EchoNode(token.contents.split()[1:])
|
return EchoNode(token.contents.split()[1:])
|
||||||
|
|
||||||
|
def do_upper(value):
|
||||||
|
return value.upper()
|
||||||
|
|
||||||
register.tag("echo", do_echo)
|
register.tag("echo", do_echo)
|
||||||
|
register.tag("other_echo", do_echo)
|
||||||
|
register.filter("upper", do_upper)
|
||||||
|
|
||||||
template.libraries['testtags'] = register
|
template.libraries['testtags'] = register
|
||||||
|
|
||||||
|
@ -354,6 +359,10 @@ class Templates(unittest.TestCase):
|
||||||
old_invalid = settings.TEMPLATE_STRING_IF_INVALID
|
old_invalid = settings.TEMPLATE_STRING_IF_INVALID
|
||||||
expected_invalid_str = 'INVALID'
|
expected_invalid_str = 'INVALID'
|
||||||
|
|
||||||
|
#Set ALLOWED_INCLUDE_ROOTS so that ssi works.
|
||||||
|
old_allowed_include_roots = settings.ALLOWED_INCLUDE_ROOTS
|
||||||
|
settings.ALLOWED_INCLUDE_ROOTS = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
# Warm the URL reversing cache. This ensures we don't pay the cost
|
# Warm the URL reversing cache. This ensures we don't pay the cost
|
||||||
# warming the cache during one of the tests.
|
# warming the cache during one of the tests.
|
||||||
urlresolvers.reverse('regressiontests.templates.views.client_action',
|
urlresolvers.reverse('regressiontests.templates.views.client_action',
|
||||||
|
@ -416,6 +425,7 @@ class Templates(unittest.TestCase):
|
||||||
deactivate()
|
deactivate()
|
||||||
settings.TEMPLATE_DEBUG = old_td
|
settings.TEMPLATE_DEBUG = old_td
|
||||||
settings.TEMPLATE_STRING_IF_INVALID = old_invalid
|
settings.TEMPLATE_STRING_IF_INVALID = old_invalid
|
||||||
|
settings.ALLOWED_INCLUDE_ROOTS = old_allowed_include_roots
|
||||||
|
|
||||||
self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
|
self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
|
||||||
('-'*70, ("\n%s\n" % ('-'*70)).join(failures)))
|
('-'*70, ("\n%s\n" % ('-'*70)).join(failures)))
|
||||||
|
@ -1056,6 +1066,19 @@ class Templates(unittest.TestCase):
|
||||||
'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
|
'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
|
||||||
'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
|
'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
|
||||||
|
|
||||||
|
### LOADING TAG LIBRARIES #################################################
|
||||||
|
|
||||||
|
# {% load %} tag, importing individual tags
|
||||||
|
'load1': ("{% load echo from testtags %}{% echo this that theother %}", {}, 'this that theother'),
|
||||||
|
'load2': ("{% load echo other_echo from testtags %}{% echo this that theother %} {% other_echo and another thing %}", {}, 'this that theother and another thing'),
|
||||||
|
'load3': ("{% load echo upper from testtags %}{% echo this that theother %} {{ statement|upper }}", {'statement': 'not shouting'}, 'this that theother NOT SHOUTING'),
|
||||||
|
|
||||||
|
# {% load %} tag errors
|
||||||
|
'load4': ("{% load echo other_echo bad_tag from testtags %}", {}, template.TemplateSyntaxError),
|
||||||
|
'load5': ("{% load echo other_echo bad_tag from %}", {}, template.TemplateSyntaxError),
|
||||||
|
'load6': ("{% load from testtags %}", {}, template.TemplateSyntaxError),
|
||||||
|
'load7': ("{% load echo from bad_library %}", {}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
### I18N ##################################################################
|
### I18N ##################################################################
|
||||||
|
|
||||||
# {% spaceless %} tag
|
# {% spaceless %} tag
|
||||||
|
@ -1179,6 +1202,30 @@ class Templates(unittest.TestCase):
|
||||||
'{% endfor %},' + \
|
'{% endfor %},' + \
|
||||||
'{% endfor %}',
|
'{% endfor %}',
|
||||||
{}, ''),
|
{}, ''),
|
||||||
|
### SSI TAG ########################################################
|
||||||
|
|
||||||
|
# Test normal behavior
|
||||||
|
'old-ssi01': ('{%% ssi %s %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', 'ssi_include.html'), {}, 'This is for testing an ssi include. {{ test }}\n'),
|
||||||
|
'old-ssi02': ('{%% ssi %s %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'not_here'), {}, ''),
|
||||||
|
|
||||||
|
# Test parsed output
|
||||||
|
'old-ssi06': ('{%% ssi %s parsed %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', 'ssi_include.html'), {'test': 'Look ma! It parsed!'}, 'This is for testing an ssi include. Look ma! It parsed!\n'),
|
||||||
|
'old-ssi07': ('{%% ssi %s parsed %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'not_here'), {'test': 'Look ma! It parsed!'}, ''),
|
||||||
|
|
||||||
|
# Future compatibility
|
||||||
|
# Test normal behavior
|
||||||
|
'ssi01': ('{%% load ssi from future %%}{%% ssi "%s" %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', 'ssi_include.html'), {}, 'This is for testing an ssi include. {{ test }}\n'),
|
||||||
|
'ssi02': ('{%% load ssi from future %%}{%% ssi "%s" %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'not_here'), {}, ''),
|
||||||
|
'ssi03': ("{%% load ssi from future %%}{%% ssi '%s' %%}" % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'not_here'), {}, ''),
|
||||||
|
|
||||||
|
# Test passing as a variable
|
||||||
|
'ssi04': ('{% load ssi from future %}{% ssi ssi_file %}', {'ssi_file': os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', 'ssi_include.html')}, 'This is for testing an ssi include. {{ test }}\n'),
|
||||||
|
'ssi05': ('{% load ssi from future %}{% ssi ssi_file %}', {'ssi_file': 'no_file'}, ''),
|
||||||
|
|
||||||
|
# Test parsed output
|
||||||
|
'ssi06': ('{%% load ssi from future %%}{%% ssi "%s" parsed %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', 'ssi_include.html'), {'test': 'Look ma! It parsed!'}, 'This is for testing an ssi include. Look ma! It parsed!\n'),
|
||||||
|
'ssi07': ('{%% load ssi from future %%}{%% ssi "%s" parsed %%}' % os.path.join(os.path.dirname(os.path.abspath(__file__)), 'not_here'), {'test': 'Look ma! It parsed!'}, ''),
|
||||||
|
|
||||||
|
|
||||||
### TEMPLATETAG TAG #######################################################
|
### TEMPLATETAG TAG #######################################################
|
||||||
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
||||||
|
@ -1244,41 +1291,91 @@ class Templates(unittest.TestCase):
|
||||||
'legacyurl16a': ("{% url regressiontests.templates.views.client_action action='update',id='1' %}", {}, '/url_tag/client/1/update/'),
|
'legacyurl16a': ("{% url regressiontests.templates.views.client_action action='update',id='1' %}", {}, '/url_tag/client/1/update/'),
|
||||||
'legacyurl17': ('{% url regressiontests.templates.views.client_action client_id=client.my_id,action=action %}', {'client': {'my_id': 1}, 'action': 'update'}, '/url_tag/client/1/update/'),
|
'legacyurl17': ('{% url regressiontests.templates.views.client_action client_id=client.my_id,action=action %}', {'client': {'my_id': 1}, 'action': 'update'}, '/url_tag/client/1/update/'),
|
||||||
|
|
||||||
'url01': ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
'old-url01': ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
||||||
'url02': ('{% url regressiontests.templates.views.client_action id=client.id action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
'old-url02': ('{% url regressiontests.templates.views.client_action id=client.id action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
'url02a': ('{% url regressiontests.templates.views.client_action client.id "update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
'old-url02a': ('{% url regressiontests.templates.views.client_action client.id "update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
'url02b': ("{% url regressiontests.templates.views.client_action id=client.id action='update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
'old-url02b': ("{% url regressiontests.templates.views.client_action id=client.id action='update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
'url02c': ("{% url regressiontests.templates.views.client_action client.id 'update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
'old-url02c': ("{% url regressiontests.templates.views.client_action client.id 'update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
'url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
|
'old-url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
|
||||||
'url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
|
'old-url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
|
||||||
'url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
'old-url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'url06': (u'{% url метка_оператора_2 tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
'old-url06': (u'{% url метка_оператора_2 tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'url07': (u'{% url regressiontests.templates.views.client2 tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
'old-url07': (u'{% url regressiontests.templates.views.client2 tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'url08': (u'{% url метка_оператора v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
'old-url08': (u'{% url метка_оператора v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'url09': (u'{% url метка_оператора_2 tag=v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
'old-url09': (u'{% url метка_оператора_2 tag=v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'url10': ('{% url regressiontests.templates.views.client_action id=client.id action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
|
'old-url10': ('{% url regressiontests.templates.views.client_action id=client.id action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
|
||||||
'url11': ('{% url regressiontests.templates.views.client_action id=client.id action="==" %}', {'client': {'id': 1}}, '/url_tag/client/1/==/'),
|
'old-url11': ('{% url regressiontests.templates.views.client_action id=client.id action="==" %}', {'client': {'id': 1}}, '/url_tag/client/1/==/'),
|
||||||
'url12': ('{% url regressiontests.templates.views.client_action id=client.id action="," %}', {'client': {'id': 1}}, '/url_tag/client/1/,/'),
|
'old-url12': ('{% url regressiontests.templates.views.client_action id=client.id action="," %}', {'client': {'id': 1}}, '/url_tag/client/1/,/'),
|
||||||
'url13': ('{% url regressiontests.templates.views.client_action id=client.id action=arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
'old-url13': ('{% url regressiontests.templates.views.client_action id=client.id action=arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
||||||
'url14': ('{% url regressiontests.templates.views.client_action client.id arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
'old-url14': ('{% url regressiontests.templates.views.client_action client.id arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
||||||
'url15': ('{% url regressiontests.templates.views.client_action 12 "test" %}', {}, '/url_tag/client/12/test/'),
|
'old-url15': ('{% url regressiontests.templates.views.client_action 12 "test" %}', {}, '/url_tag/client/12/test/'),
|
||||||
'url18': ('{% url regressiontests.templates.views.client "1,2" %}', {}, '/url_tag/client/1,2/'),
|
'old-url18': ('{% url regressiontests.templates.views.client "1,2" %}', {}, '/url_tag/client/1,2/'),
|
||||||
|
|
||||||
# Failures
|
# Failures
|
||||||
'url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
|
'old-url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail02': ('{% url no_such_view %}', {}, urlresolvers.NoReverseMatch),
|
'old-url-fail02': ('{% url no_such_view %}', {}, urlresolvers.NoReverseMatch),
|
||||||
'url-fail03': ('{% url regressiontests.templates.views.client %}', {}, urlresolvers.NoReverseMatch),
|
'old-url-fail03': ('{% url regressiontests.templates.views.client %}', {}, urlresolvers.NoReverseMatch),
|
||||||
'url-fail04': ('{% url view id, %}', {}, template.TemplateSyntaxError),
|
'old-url-fail04': ('{% url view id, %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail05': ('{% url view id= %}', {}, template.TemplateSyntaxError),
|
'old-url-fail05': ('{% url view id= %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail06': ('{% url view a.id=id %}', {}, template.TemplateSyntaxError),
|
'old-url-fail06': ('{% url view a.id=id %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail07': ('{% url view a.id!id %}', {}, template.TemplateSyntaxError),
|
'old-url-fail07': ('{% url view a.id!id %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail08': ('{% url view id="unterminatedstring %}', {}, template.TemplateSyntaxError),
|
'old-url-fail08': ('{% url view id="unterminatedstring %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail09': ('{% url view id=", %}', {}, template.TemplateSyntaxError),
|
'old-url-fail09': ('{% url view id=", %}', {}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
# {% url ... as var %}
|
# {% url ... as var %}
|
||||||
'url-asvar01': ('{% url regressiontests.templates.views.index as url %}', {}, ''),
|
'old-url-asvar01': ('{% url regressiontests.templates.views.index as url %}', {}, ''),
|
||||||
'url-asvar02': ('{% url regressiontests.templates.views.index as url %}{{ url }}', {}, '/url_tag/'),
|
'old-url-asvar02': ('{% url regressiontests.templates.views.index as url %}{{ url }}', {}, '/url_tag/'),
|
||||||
'url-asvar03': ('{% url no_such_view as url %}{{ url }}', {}, ''),
|
'old-url-asvar03': ('{% url no_such_view as url %}{{ url }}', {}, ''),
|
||||||
|
|
||||||
|
# forward compatibility
|
||||||
|
# Successes
|
||||||
|
'url01': ('{% load url from future %}{% url "regressiontests.templates.views.client" client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
||||||
|
'url02': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" id=client.id action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
|
'url02a': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" client.id "update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
|
'url02b': ("{% load url from future %}{% url 'regressiontests.templates.views.client_action' id=client.id action='update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
|
'url02c': ("{% load url from future %}{% url 'regressiontests.templates.views.client_action' client.id 'update' %}", {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
|
'url03': ('{% load url from future %}{% url "regressiontests.templates.views.index" %}', {}, '/url_tag/'),
|
||||||
|
'url04': ('{% load url from future %}{% url "named.client" client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
|
||||||
|
'url05': (u'{% load url from future %}{% url "метка_оператора" v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
|
'url06': (u'{% load url from future %}{% url "метка_оператора_2" tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
|
'url07': (u'{% load url from future %}{% url "regressiontests.templates.views.client2" tag=v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
|
'url08': (u'{% load url from future %}{% url "метка_оператора" v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
|
'url09': (u'{% load url from future %}{% url "метка_оператора_2" tag=v %}', {'v': 'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
|
'url10': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" id=client.id action="two words" %}', {'client': {'id': 1}}, '/url_tag/client/1/two%20words/'),
|
||||||
|
'url11': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" id=client.id action="==" %}', {'client': {'id': 1}}, '/url_tag/client/1/==/'),
|
||||||
|
'url12': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" id=client.id action="," %}', {'client': {'id': 1}}, '/url_tag/client/1/,/'),
|
||||||
|
'url13': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" id=client.id action=arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
||||||
|
'url14': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" client.id arg|join:"-" %}', {'client': {'id': 1}, 'arg':['a','b']}, '/url_tag/client/1/a-b/'),
|
||||||
|
'url15': ('{% load url from future %}{% url "regressiontests.templates.views.client_action" 12 "test" %}', {}, '/url_tag/client/12/test/'),
|
||||||
|
'url18': ('{% load url from future %}{% url "regressiontests.templates.views.client" "1,2" %}', {}, '/url_tag/client/1,2/'),
|
||||||
|
|
||||||
|
'url19': ('{% load url from future %}{% url named_url client.id %}', {'named_url': 'regressiontests.templates.views.client', 'client': {'id': 1}}, '/url_tag/client/1/'),
|
||||||
|
|
||||||
|
# Failures
|
||||||
|
'url-fail01': ('{% load url from future %}{% url %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail02': ('{% load url from future %}{% url "no_such_view" %}', {}, urlresolvers.NoReverseMatch),
|
||||||
|
'url-fail03': ('{% load url from future %}{% url "regressiontests.templates.views.client" %}', {}, urlresolvers.NoReverseMatch),
|
||||||
|
'url-fail04': ('{% load url from future %}{% url "view" id, %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail05': ('{% load url from future %}{% url "view" id= %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail06': ('{% load url from future %}{% url "view" a.id=id %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail07': ('{% load url from future %}{% url "view" a.id!id %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail08': ('{% load url from future %}{% url "view" id="unterminatedstring %}', {}, template.TemplateSyntaxError),
|
||||||
|
'url-fail09': ('{% load url from future %}{% url "view" id=", %}', {}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
|
'url-fail11': ('{% load url from future %}{% url named_url %}', {}, urlresolvers.NoReverseMatch),
|
||||||
|
'url-fail12': ('{% load url from future %}{% url named_url %}', {'named_url': 'no_such_view'}, urlresolvers.NoReverseMatch),
|
||||||
|
'url-fail13': ('{% load url from future %}{% url named_url %}', {'named_url': 'regressiontests.templates.views.client'}, urlresolvers.NoReverseMatch),
|
||||||
|
'url-fail14': ('{% load url from future %}{% url named_url id, %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
'url-fail15': ('{% load url from future %}{% url named_url id= %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
'url-fail16': ('{% load url from future %}{% url named_url a.id=id %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
'url-fail17': ('{% load url from future %}{% url named_url a.id!id %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
'url-fail18': ('{% load url from future %}{% url named_url id="unterminatedstring %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
'url-fail19': ('{% load url from future %}{% url named_url id=", %}', {'named_url': 'view'}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
|
# {% url ... as var %}
|
||||||
|
'url-asvar01': ('{% load url from future %}{% url "regressiontests.templates.views.index" as url %}', {}, ''),
|
||||||
|
'url-asvar02': ('{% load url from future %}{% url "regressiontests.templates.views.index" as url %}{{ url }}', {}, '/url_tag/'),
|
||||||
|
'url-asvar03': ('{% load url from future %}{% url "no_such_view" as url %}{{ url }}', {}, ''),
|
||||||
|
|
||||||
### CACHE TAG ######################################################
|
### CACHE TAG ######################################################
|
||||||
'cache01': ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
|
'cache01': ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
|
||||||
|
|
|
@ -3,8 +3,9 @@ from django.template import Template, Context
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
||||||
def inner_view(request):
|
def inner_view(request):
|
||||||
content = Template('{% url outer as outer_url %}outer:{{ outer_url }},'
|
content = Template('{% load url from future %}'
|
||||||
'{% url inner as inner_url %}inner:{{ inner_url }}').render(Context())
|
'{% url "outer" as outer_url %}outer:{{ outer_url }},'
|
||||||
|
'{% url "inner" as inner_url %}inner:{{ inner_url }}').render(Context())
|
||||||
return HttpResponse(content)
|
return HttpResponse(content)
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
|
|
Loading…
Reference in New Issue