summaryrefslogtreecommitdiff
path: root/django/template
diff options
context:
space:
mode:
authorRobin Munn <robin.munn@gmail.com>2006-11-08 04:50:01 +0000
committerRobin Munn <robin.munn@gmail.com>2006-11-08 04:50:01 +0000
commitdadfca08c0db567ce33284aaa8eb388cf667a836 (patch)
treeab7255eeee1bbe03d95652cc74a3843fa052d8ac /django/template
parent0b059aa4eadc1d95ceca3a32821b65a9fb2a53e8 (diff)
sqlalchemy: Merged revisions 3918 to 4053 from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/sqlalchemy@4054 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/template')
-rw-r--r--django/template/__init__.py23
-rw-r--r--django/template/context.py2
-rw-r--r--django/template/defaultfilters.py6
-rw-r--r--django/template/defaulttags.py57
-rw-r--r--django/template/loaders/app_directories.py4
5 files changed, 65 insertions, 27 deletions
diff --git a/django/template/__init__.py b/django/template/__init__.py
index af8f37a474..5affafeba9 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -66,6 +66,7 @@ __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
TOKEN_TEXT = 0
TOKEN_VAR = 1
TOKEN_BLOCK = 2
+TOKEN_COMMENT = 3
# template syntax constants
FILTER_SEPARATOR = '|'
@@ -75,6 +76,8 @@ BLOCK_TAG_START = '{%'
BLOCK_TAG_END = '%}'
VARIABLE_TAG_START = '{{'
VARIABLE_TAG_END = '}}'
+COMMENT_TAG_START = '{#'
+COMMENT_TAG_END = '#}'
SINGLE_BRACE_START = '{'
SINGLE_BRACE_END = '}'
@@ -85,8 +88,9 @@ ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01
UNKNOWN_SOURCE="&lt;unknown source&gt;"
# match a variable or block tag and capture the entire tag, including start/end delimiters
-tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
- re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END)))
+tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
+ re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
+ re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
# global dictionary of libraries that have been loaded using get_library
libraries = {}
@@ -163,12 +167,12 @@ def compile_string(template_string, origin):
class Token(object):
def __init__(self, token_type, contents):
- "The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK"
+ "The token_type must be TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK or TOKEN_COMMENT"
self.token_type, self.contents = token_type, contents
def __str__(self):
return '<%s token: "%s...">' % \
- ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block'}[self.token_type],
+ ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block', TOKEN_COMMENT: 'Comment'}[self.token_type],
self.contents[:20].replace('\n', ''))
def split_contents(self):
@@ -191,6 +195,8 @@ class Lexer(object):
token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip())
elif token_string.startswith(BLOCK_TAG_START):
token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip())
+ elif token_string.startswith(COMMENT_TAG_START):
+ token = Token(TOKEN_COMMENT, '')
else:
token = Token(TOKEN_TEXT, token_string)
return token
@@ -862,8 +868,11 @@ class Library(object):
dict = func(*args)
if not getattr(self, 'nodelist', False):
- from django.template.loader import get_template
- t = get_template(file_name)
+ from django.template.loader import get_template, select_template
+ if hasattr(file_name, '__iter__'):
+ t = select_template(file_name)
+ else:
+ t = get_template(file_name)
self.nodelist = t.nodelist
return self.nodelist.render(context_class(dict))
@@ -877,7 +886,7 @@ def get_library(module_name):
lib = libraries.get(module_name, None)
if not lib:
try:
- mod = __import__(module_name, '', '', [''])
+ mod = __import__(module_name, {}, {}, [''])
except ImportError, e:
raise InvalidTemplateLibrary, "Could not load template library from %s, %s" % (module_name, e)
try:
diff --git a/django/template/context.py b/django/template/context.py
index 6d9efdc7ec..ba23e95ab7 100644
--- a/django/template/context.py
+++ b/django/template/context.py
@@ -69,7 +69,7 @@ def get_standard_processors():
i = path.rfind('.')
module, attr = path[:i], path[i+1:]
try:
- mod = __import__(module, '', '', [attr])
+ mod = __import__(module, {}, {}, [attr])
except ImportError, e:
raise ImproperlyConfigured, 'Error importing request processor module %s: "%s"' % (module, e)
try:
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index cf1d3d5f6d..969ef7b28b 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -421,7 +421,11 @@ def filesizeformat(bytes):
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
bytes, etc).
"""
- bytes = float(bytes)
+ try:
+ bytes = float(bytes)
+ except TypeError:
+ return "0 bytes"
+
if bytes < 1024:
return "%d byte%s" % (bytes, bytes != 1 and 's' or '')
if bytes < 1024 * 1024:
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 07e579bf9d..3f3f4bda56 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -1,7 +1,7 @@
"Default tags used by the template system, available to all templates."
from django.template import Node, NodeList, Template, Context, resolve_variable
-from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END
+from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
from django.template import get_library, Library, InvalidTemplateLibrary
from django.conf import settings
import sys
@@ -124,17 +124,27 @@ class ForNode(Node):
return nodelist.render(context)
class IfChangedNode(Node):
- def __init__(self, nodelist):
+ def __init__(self, nodelist, *varlist):
self.nodelist = nodelist
self._last_seen = None
+ self._varlist = varlist
def render(self, context):
if context.has_key('forloop') and context['forloop']['first']:
self._last_seen = None
- content = self.nodelist.render(context)
- if content != self._last_seen:
+ try:
+ if self._varlist:
+ # Consider multiple parameters.
+ # This automatically behaves like a OR evaluation of the multiple variables.
+ compare_to = [resolve_variable(var, context) for var in self._varlist]
+ else:
+ compare_to = self.nodelist.render(context)
+ except VariableDoesNotExist:
+ compare_to = None
+
+ if compare_to != self._last_seen:
firstloop = (self._last_seen == None)
- self._last_seen = content
+ self._last_seen = compare_to
context.push()
context['ifchanged'] = {'firstloop': firstloop}
content = self.nodelist.render(context)
@@ -295,6 +305,8 @@ class TemplateTagNode(Node):
'closevariable': VARIABLE_TAG_END,
'openbrace': SINGLE_BRACE_START,
'closebrace': SINGLE_BRACE_END,
+ 'opencomment': COMMENT_TAG_START,
+ 'closecomment': COMMENT_TAG_END,
}
def __init__(self, tagtype):
@@ -632,23 +644,34 @@ def ifchanged(parser, token):
"""
Check if a value has changed from the last iteration of a loop.
- The 'ifchanged' block tag is used within a loop. It checks its own rendered
- contents against its previous state and only displays its content if the
- value has changed::
+ The 'ifchanged' block tag is used within a loop. It has two possible uses.
- <h1>Archive for {{ year }}</h1>
+ 1. Checks its own rendered contents against its previous state and only
+ displays the content if it has changed. For example, this displays a list of
+ days, only displaying the month if it changes::
- {% for date in days %}
- {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
- <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
- {% endfor %}
+ <h1>Archive for {{ year }}</h1>
+
+ {% for date in days %}
+ {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
+ <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
+ {% endfor %}
+
+ 2. If given a variable, check whether that variable has changed. For example, the
+ following shows the date every time it changes, but only shows the hour if both
+ the hour and the date have changed::
+
+ {% for date in days %}
+ {% ifchanged date.date %} {{ date.date }} {% endifchanged %}
+ {% ifchanged date.hour date.date %}
+ {{ date.hour }}
+ {% endifchanged %}
+ {% endfor %}
"""
bits = token.contents.split()
- if len(bits) != 1:
- raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
nodelist = parser.parse(('endifchanged',))
parser.delete_first_token()
- return IfChangedNode(nodelist)
+ return IfChangedNode(nodelist, *bits[1:])
ifchanged = register.tag(ifchanged)
#@register.tag
@@ -831,6 +854,8 @@ def templatetag(parser, token):
``closevariable`` ``}}``
``openbrace`` ``{``
``closebrace`` ``}``
+ ``opencomment`` ``{#``
+ ``closecomment`` ``#}``
================== =======
"""
bits = token.contents.split()
diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py
index 8a9bfef4b6..c4e91df929 100644
--- a/django/template/loaders/app_directories.py
+++ b/django/template/loaders/app_directories.py
@@ -15,9 +15,9 @@ for app in settings.INSTALLED_APPS:
m, a = app[:i], app[i+1:]
try:
if a is None:
- mod = __import__(m, '', '', [])
+ mod = __import__(m, {}, {}, [])
else:
- mod = getattr(__import__(m, '', '', [a]), a)
+ mod = getattr(__import__(m, {}, {}, [a]), a)
except ImportError, e:
raise ImproperlyConfigured, 'ImportError %s: %s' % (app, e.args[0])
template_dir = os.path.join(os.path.dirname(mod.__file__), 'templates')