diff --git a/django/contrib/admin/templates/admin/filter.html b/django/contrib/admin/templates/admin/filter.html
new file mode 100644
index 0000000000..e79a14a2ce
--- /dev/null
+++ b/django/contrib/admin/templates/admin/filter.html
@@ -0,0 +1,7 @@
+
Error in Template
-{{message}}
-{{traceback}}
+{{message|escape}}
+{{traceback|escape}}
{%if top%}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index ea1b7bf619..3f155564c0 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -209,8 +209,6 @@ def items_for_result(cl, result):
else:
yield ('
%s | ' % (row_class, result_repr))
-
-
def results(cl):
for res in cl.result_list:
yield list(items_for_result(cl,res))
@@ -224,7 +222,6 @@ def result_list(cl):
result_list = inclusion_tag("admin/change_list_results")(result_list)
-
#@simple_tag
def date_hierarchy(cl):
lookup_opts, params, lookup_params, lookup_mod = \
@@ -278,10 +275,11 @@ def search_form(cl):
'search_var': SEARCH_VAR }
search_form = inclusion_tag('admin/search_form')(search_form)
-#@simple_tag
-def output_filter_spec(cl, spec):
- return spec.output(cl)
-output_filter_spec = simple_tag(output_filter_spec)
+#@inclusion_tag('admin/filter')
+def filter(cl, spec):
+ return {'title': spec.title(),
+ 'choices' : list(spec.choices(cl))}
+filter = inclusion_tag('admin/filter')(filter)
#@inclusion_tag('admin/filters')
def filters(cl):
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index 4694f8912d..7f0c5c5906 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -72,21 +72,26 @@ class FilterSpec(object):
def has_output(self):
return True
+ def choices(self, cl):
+ raise NotImplementedException()
+
+ def title(self):
+ return self.field.verbose_name
+
def output(self, cl):
t = []
if self.has_output():
- t.append(_('
By %s:
\n
\n') % self.title)
+ t.append(_('By %s:
\n\n') % self.title())
- for choice in self.choices:
+ for choice in self.choices(cl):
t.append('- %s
\n' % \
- (self.is_selected(choice) and ' class="selected"' or ''),
- self.get_query_string(choice) ,
- self.get_display(choice) )
+ ((choice['selected'] and ' class="selected"' or ''),
+ choice['query_string'] ,
+ choice['display']))
t.append('
\n\n')
return "".join(t)
class RelatedFilterSpec(FilterSpec):
-
def __init__(self, f, request, params):
super(RelatedFilterSpec, self).__init__(f, request, params)
if isinstance(f, meta.ManyToManyField):
@@ -100,20 +105,18 @@ class RelatedFilterSpec(FilterSpec):
def has_output(self):
return len(self.lookup_choices) > 1
- def output(self, cl):
- t = []
- if self.has_output():
- t.append(_('By %s:
\n\n') % self.lookup_title)
- t.append('- All
\n' % \
- ((self.lookup_val is None and ' class="selected"' or ''),
- cl.get_query_string({}, [self.lookup_kwarg])))
- for val in self.lookup_choices:
- pk_val = getattr(val, self.field.rel.to.pk.column)
- t.append('- %s
\n' % \
- ((self.lookup_val == str(pk_val) and ' class="selected"' or ''),
- cl.get_query_string( {self.lookup_kwarg: pk_val}), val))
- t.append('
\n\n')
- return "".join(t)
+ def title(self):
+ return self.lookup_title
+
+ def choices(self, cl):
+ yield {'selected': self.lookup_val is None,
+ 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
+ 'display': _('All') }
+ for val in self.lookup_choices:
+ pk_val = getattr(val, self.field.rel.to.pk.column)
+ yield { 'selected': self.lookup_val == str(pk_val),
+ 'query_string': cl.get_query_string( {self.lookup_kwarg: pk_val}),
+ 'display' : val }
FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
class ChoicesFilterSpec(FilterSpec):
@@ -123,18 +126,14 @@ class ChoicesFilterSpec(FilterSpec):
self.lookup_kwarg = '%s__exact' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
- def output(self, cl):
- t = []
- t.append(_('By %s:
\n') % self.field.verbose_name)
- t.append('- All
\n' % \
- ((self.lookup_val is None and ' class="selected"' or ''),
- cl.get_query_string( {}, [self.lookup_kwarg])))
+ def choices(self, cl):
+ yield {'selected' : self.lookup_val is None,
+ 'query_string': cl.get_query_string( {}, [self.lookup_kwarg]),
+ 'display': _('All') }
for k, v in self.field.choices:
- t.append('- %s
' % \
- ((str(k) == self.lookup_val) and ' class="selected"' or '',
- cl.get_query_string( {self.lookup_kwarg: k}), v))
- t.append('
\n\n')
- return "".join(t)
+ yield {'selected': str(k) == self.lookup_val,
+ 'query_string' : cl.get_query_string( {self.lookup_kwarg: k}),
+ 'display' : v }
FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
class DateFieldFilterSpec(FilterSpec):
@@ -161,16 +160,16 @@ class DateFieldFilterSpec(FilterSpec):
'%s__month' % f.name: str(today.month)}),
('This year', {'%s__year' % self.field.name: str(today.year)})
)
-
- def output(self, cl):
- t = []
- t.append(_('By %s:
\n') % self.field.verbose_name)
+
+ def title(self):
+ return self.field.verbose_name
+
+ def choices(self, cl):
for title, param_dict in self.links:
- t.append('- %s
\n' % \
- ((self.date_params == param_dict) and ' class="selected"' or '',
- cl.get_query_string( param_dict, self.field_generic), title))
- t.append('
\n\n')
- return "".join(t)
+ yield { 'selected' : self.date_params == param_dict,
+ 'query_string' : cl.get_query_string( param_dict, self.field_generic),
+ 'display' : title }
+
FilterSpec.register(lambda f: isinstance(f, meta.DateField), DateFieldFilterSpec)
class BooleanFieldFilterSpec(FilterSpec):
@@ -182,19 +181,20 @@ class BooleanFieldFilterSpec(FilterSpec):
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
- def output(self, cl):
- t = []
- t.append(_('By %s:
\n') % self.field.verbose_name)
+ def title(self):
+ return self.field.verbose_name
+
+ def choices(self, cl):
for k, v in (('All', None), ('Yes', '1'), ('No', '0')):
- t.append('- %s
\n' % \
- (((self.lookup_val == v and not self.lookup_val2) and ' class="selected"' or ''),
- cl.get_query_string( {self.lookup_kwarg: v}, [self.lookup_kwarg2]), k))
+ yield { 'selected' : self.lookup_val == v and not self.lookup_val2,
+ 'query_string' : cl.get_query_string( {self.lookup_kwarg: v}, [self.lookup_kwarg2]),
+ 'display': k
+ }
if isinstance(self.field, meta.NullBooleanField):
- t.append('- %s
\n' % \
- (((lookup_val2 == 'True') and ' class="selected"' or ''),
- cl.get_query_string( {self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]), 'Unknown'))
- t.append('
\n\n')
- return "".join(t)
+ yield { 'selected' : lookup_val2 == 'True',
+ 'query_string' : cl.get_query_string( {self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
+ 'display': _('Unknown')
+ }
FilterSpec.register(lambda f: isinstance(f, meta.BooleanField) or
isinstance(f, meta.NullBooleanField), BooleanFieldFilterSpec)
diff --git a/django/core/template/__init__.py b/django/core/template/__init__.py
index 937744151b..3e37b114a1 100644
--- a/django/core/template/__init__.py
+++ b/django/core/template/__init__.py
@@ -286,7 +286,8 @@ class Parser(object):
elif token.token_type == TOKEN_VAR:
if not token.contents:
self.empty_variable(token)
- self.extend_nodelist(nodelist, VariableNode(token.contents), token)
+ var_node = self.create_variable_node(token.contents)
+ self.extend_nodelist(nodelist, var_node,token)
elif token.token_type == TOKEN_BLOCK:
if token.contents in parse_until:
# put token back on token list so calling code knows why it terminated
@@ -313,6 +314,9 @@ class Parser(object):
self.unclosed_block_tag(token, parse_until)
return nodelist
+ def create_variable_node(self, contents):
+ return VariableNode(contents)
+
def create_nodelist(self):
return NodeList()
@@ -374,6 +378,9 @@ class DebugParser(Parser):
def create_nodelist(self):
return DebugNodeList()
+ def create_variable_node(self, contents):
+ return DebugVariableNode(contents)
+
def extend_nodelist(self, nodelist, node, token):
node.source = token.source
super(DebugParser, self).extend_nodelist(nodelist, node, token)
@@ -866,14 +873,28 @@ class VariableNode(Node):
def __repr__(self):
return "" % self.var_string
- def render(self, context):
- output = resolve_variable_with_filters(self.var_string, context)
+ def encode_output(self, output):
# Check type so that we don't run str() on a Unicode object
if not isinstance(output, basestring):
- output = str(output)
+ return str(output)
elif isinstance(output, unicode):
- output = output.encode(DEFAULT_CHARSET)
- return output
+ return output.encode(DEFAULT_CHARSET)
+ else:
+ return output
+
+ def render(self, context):
+ output = resolve_variable_with_filters(self.var_string, context)
+ return self.encode_output(output)
+
+class DebugVariableNode(VariableNode):
+ def render(self, context):
+ try:
+ output = resolve_variable_with_filters(self.var_string, context)
+ except TemplateSyntaxError, e:
+ if not hasattr(e, 'source'):
+ e.source = self.source
+ raise
+ return self.encode_output(output)
def register_tag(token_command, callback_function):
registered_tags[token_command] = callback_function