diff --git a/django/conf/admin_templates/admin_change_form.html b/django/conf/admin_templates/admin_change_form.html
index 2beac80272..692de223af 100644
--- a/django/conf/admin_templates/admin_change_form.html
+++ b/django/conf/admin_templates/admin_change_form.html
@@ -87,7 +87,7 @@
{% if auto_populated_fields %}
{% endif %}
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 449d25d01e..c5e560c9e1 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -110,7 +110,7 @@ IGNORABLE_404_ENDS = ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi', 'fav
SECRET_KEY = ''
# Path to the "jing" executable -- needed to validate XMLFields
-JING_PATH = "/usr/bin/jng"
+JING_PATH = "/usr/bin/jing"
##############
# MIDDLEWARE #
diff --git a/django/core/defaulttags.py b/django/core/defaulttags.py
index d5bfec7cf0..41595fcee0 100644
--- a/django/core/defaulttags.py
+++ b/django/core/defaulttags.py
@@ -227,6 +227,15 @@ class SsiNode(template.Node):
return '' # Fail silently for invalid included templates.
return output
+
+class ConstantIncludeNode(template.Node):
+ def __init__(self, template_path):
+ t = template_loader.get_template(template_path)
+ self.nodelist = t.nodelist
+
+ def render(self, context):
+ return self.nodelist.render(context)
+
class IncludeNode(template.Node):
def __init__(self, template_path_var):
self.template_path_var = template_path_var
@@ -631,6 +640,10 @@ def do_include(parser, token):
parsed = False
if len(bits) != 2:
raise template.TemplateSyntaxError, "'include' tag takes one argument: the path to the template to be included"
+
+ path = bits[1]
+ if path[0] in ('"', "'") and path[-1] == path[0]:
+ return ConstantIncludeNode(path[1:-1])
return IncludeNode(bits[1])
def do_load(parser, token):
@@ -648,8 +661,8 @@ def do_load(parser, token):
# check at compile time that the module can be imported
try:
LoadNode.load_taglib(taglib)
- except ImportError:
- raise template.TemplateSyntaxError, "'%s' is not a valid tag library" % taglib
+ except ImportError, e:
+ raise template.TemplateSyntaxError, "'%s' is not a valid tag library, %s" % (taglib, e)
return LoadNode(taglib)
def do_now(parser, token):
diff --git a/django/core/template_decorators.py b/django/core/template_decorators.py
new file mode 100644
index 0000000000..3b32e694e7
--- /dev/null
+++ b/django/core/template_decorators.py
@@ -0,0 +1,70 @@
+from inspect import getargspec
+from django.core import template
+from django.core.template_loader import render_to_string, get_template
+from django.utils.functional import curry
+
+def gen_compile_func(params, defaults, name, node_class, parser, token):
+ #look in tags for
+ bits = token.contents.split()[1:]
+ bmax = len(params)
+ def_len = defaults and len(defaults) or 0
+ bmin = bmax - def_len
+ if( len(bits) < bmin or len(bits) > bmax ):
+ if bmin == bmax:
+ message = "%s takes %s arguments" % (name, bmin)
+ else:
+ message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
+ raise template.TemplateSyntaxError(message)
+ return node_class(bits)
+
+
+def simple_tag(func):
+ (params,_, _, defaults) = getargspec(func)
+ class TNode(template.Node):
+ def __init__(self, vars_to_resolve):
+ #get the vars to resolve
+ self.vars_to_resolve = vars_to_resolve
+
+ def render(self, context):
+ resolved_vars = [template.resolve_variable(var, context)
+ for var in self.vars_to_resolve]
+ return func(*resolved_vars)
+ compile_func = curry(gen_compile_func, params, defaults, func.__name__, TNode)
+ compile_func.__doc__ = func.__doc__
+ template.register_tag(func.__name__, compile_func)
+ return func
+
+
+def inclusion_tag(file_name, context_class=template.Context, takes_context=False):
+ def dec(func):
+ (params,_, _, defaults) = getargspec(func)
+ if takes_context:
+ if params[0] == 'context':
+ params = params[1:]
+ else:
+ raise template.TemplateSyntaxError("Any tag function decorated with takes_context=True must have a first argument of 'context'" )
+ class TNode(template.Node):
+ def __init__(self, vars_to_resolve):
+ self.vars_to_resolve = vars_to_resolve
+
+ def render(self, context):
+ resolved_vars = [template.resolve_variable(var, context)
+ for var in self.vars_to_resolve]
+ if takes_context:
+ args = [context] + resolved_vars
+ else:
+ args = resolved_vars
+
+ dict = func(*args)
+
+ if not getattr(self, 'nodelist', False):
+ t = get_template(file_name)
+ self.nodelist = t.nodelist
+ return self.nodelist.render(context_class(dict))
+
+ compile_func = curry(gen_compile_func, params, defaults, func.__name__, TNode)
+ compile_func.__doc__ = func.__doc__
+ template.register_tag(func.__name__, compile_func)
+ return func
+ return dec
+
diff --git a/django/templatetags/admin_modify.py b/django/templatetags/admin_modify.py
index c52505e044..2938f47a58 100644
--- a/django/templatetags/admin_modify.py
+++ b/django/templatetags/admin_modify.py
@@ -5,6 +5,8 @@ from django.utils.text import capfirst
from django.utils.html import escape
from django.utils.functional import curry
+from django.core.template_decorators import simple_tag, inclusion_tag
+
from django.views.admin.main import AdminBoundField
import re
@@ -13,21 +15,15 @@ word_re = re.compile('[A-Z][a-z]+')
def class_name_to_underscored(name):
return '_'.join([ s.lower() for s in word_re.findall(name)[:-1] ])
-
-class IncludeAdminScriptNode(template.Node):
- def __init__(self, var):
- self.var = var
-
- def render(self, context):
- resolved = template.resolve_variable(self.var, context)
+#@simple_tag
+def include_admin_script(script_path):
return '' % \
- (ADMIN_MEDIA_PREFIX, resolved)
-
-class SubmitRowNode(template.Node):
- def __init__(self):
- pass
+ (ADMIN_MEDIA_PREFIX, script_path)
+include_admin_script = simple_tag(include_admin_script)
- def render(self, context):
+
+#@inclusion_tag('admin_submit_line', takes_context=True)
+def submit_row(context):
change = context['change']
add = context['add']
show_delete = context['show_delete']
@@ -36,8 +32,7 @@ class SubmitRowNode(template.Node):
has_delete_permission = context['has_delete_permission']
is_popup = context['is_popup']
-
- output = render_to_string('admin_submit_line', {
+ return {
'onclick_attrib' : (ordered_objects and change
and 'onclick="submitOrderForm();"' or ''),
'show_delete_link' : (not is_popup and has_delete_permission
@@ -46,50 +41,35 @@ class SubmitRowNode(template.Node):
'show_save_and_add_another': not is_popup and (not save_as or add),
'show_save_and_continue': not is_popup,
'show_save': True
- }, context);
- context.pop()
- return output;
+ }
-class AdminFieldBoundNode(template.Node):
- def __init__(self, argument):
- self.argument = argument
+srdec = inclusion_tag('admin_submit_line', takes_context=True)
+submit_row = srdec(submit_row)
+
+#@simple_tag
+def field_label(bound_field):
+ class_names = []
+ if isinstance(bound_field.field, meta.BooleanField):
+ class_names.append("vCheckboxLabel")
+ else:
+ if not bound_field.field.blank:
+ class_names.append('required')
+ if not bound_field.first:
+ class_names.append('inline')
- def render(self, context):
- argument_val = template.resolve_variable(self.argument, context)
- if (isinstance(argument_val, list)):
- bound_fields = argument_val
- else:
- bound_fields = [argument_val]
- add = context['add']
- change = context['change']
-
- context.push()
- context['bound_fields'] = bound_fields
- context['class_names'] = " ".join(self.get_class_names(bound_fields))
- t = template_loader.get_template("admin_field")
- output = t.render(context)
- context.pop()
-
- return output
+ class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
+ return ' ' % \
+ (bound_field.element_id, class_str,
+ capfirst(bound_field.field.verbose_name) )
+field_label = simple_tag(field_label)
- def get_class_names(self, bound_fields):
- class_names = ['form-row']
- for bound_field in bound_fields:
- for f in bound_field.form_fields:
- if f.errors():
- class_names.append('errors')
- break
-
- # Assumes BooleanFields won't be stacked next to each other!
- if isinstance(bound_fields[0].field, meta.BooleanField):
- class_names.append('checkbox-row')
-
- return class_names
-
class FieldWidgetNode(template.Node):
def __init__(self, bound_field_var):
self.bound_field_var = bound_field_var
+ self.nodelists = {}
+ t = template_loader.get_template("widget/default")
+ self.default = t.nodelist
def render(self, context):
@@ -100,22 +80,26 @@ class FieldWidgetNode(template.Node):
context.push()
context['bound_field'] = bound_field
klass = bound_field.field.__class__
- t = None
- while klass:
- try:
- field_class_name = klass.__name__
- template_name = "widget/%s" % \
- class_name_to_underscored(field_class_name)
-
- t = template_loader.get_template(template_name)
- break
- except template.TemplateDoesNotExist:
- klass = (len(klass.__bases__) > 0) and klass.__bases__[0] or None
-
- if t == None:
- t = template_loader.get_template("widget/default")
-
- output = t.render(context)
+ if not self.nodelists.has_key(klass):
+ t = None
+ while klass:
+ try:
+ field_class_name = klass.__name__
+ template_name = "widget/%s" % \
+ class_name_to_underscored(field_class_name)
+ t = template_loader.get_template(template_name)
+ break
+ except template.TemplateDoesNotExist:
+ klass = bool(klass.__bases__) and klass.__bases__[0] or None
+
+ if t == None:
+ nodelist = self.default
+ else:
+ nodelist = t.nodelist
+
+ self.nodelists[klass] = nodelist
+
+ output = self.nodelists[klass].render(context)
context.pop()
return output
@@ -177,71 +161,38 @@ class EditInlineNode(template.Node):
context['num_headers'] = len(field_wrapper_list)
context['original_row_needed'] = max([fw.use_raw_id_admin() for fw in field_wrapper_list])
# context['name_prefix'] = "%s." % (var_name,)
-
-class FieldLabelNode(template.Node):
- def __init__(self, bound_field_var):
- self.bound_field_var = bound_field_var
-
- def render(self, context):
- bound_field = template.resolve_variable(self.bound_field_var, context)
- class_names = []
- if isinstance(bound_field.field, meta.BooleanField):
- class_names.append("vCheckboxLabel")
- else:
- if not bound_field.field.blank:
- class_names.append('required')
- if not bound_field.first:
- class_names.append('inline')
-
- class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
- return ' ' % (bound_field.element_id, class_str, capfirst(bound_field.field.verbose_name) )
-class OutputAllNode(template.Node):
- def __init__(self, form_fields_var):
- self.form_fields_var = form_fields_var
-
- def render(self, context):
- form_fields = template.resolve_variable(self.form_fields_var, context)
- return ''.join([str(f) for f in form_fields])
-class AutoPopulatedFieldScriptNode(template.Node):
- def __init__(self, auto_pop_var):
- self.auto_pop_var = auto_pop_var
+#@simple_tag
+def output_all(form_fields):
+ return ''.join([str(f) for f in form_fields])
+output_all = simple_tag(output_all)
- def render(self,context):
- auto_pop_fields = template.resolve_variable(self.auto_pop_var, context)
- change = context['change']
- for field in auto_pop_fields:
- t = []
- if change:
- t.append('document.getElementById("id_%s")._changed = true;' % field.name )
- else:
- t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
- add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
- for f in field.prepopulate_from:
- t.append('document.getElementById("id_%s").onkeyup = function() { var e = document.getElementById("id_%s"); if(e._changed) { e.value = URLify(%s, %s);} } ' % (f, field.name, add_values, field.maxlength) )
-
- return ''.join(t)
-
-class FilterInterfaceScriptMaybeNode(template.Node):
- def __init__(self, bound_field_var):
- self.bound_field_var = bound_field_var
-
- def render(self, context):
- bound_field = template.resolve_variable(self.bound_field_var, context)
- f = bound_field.field
- if f.rel and isinstance(f.rel, meta.ManyToMany) and f.rel.filter_interface:
- return '\n' % (f.name, f.verbose_name, f.rel.filter_interface-1, ADMIN_MEDIA_PREFIX)
+#@simple_tag
+def auto_populated_field_script(auto_pop_fields, change = False):
+ for field in auto_pop_fields:
+ t = []
+ if change:
+ t.append('document.getElementById("id_%s")._changed = true;' % field.name )
else:
- return ''
+ t.append('document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
-
+ add_values = ' + " " + '.join(['document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
+ for f in field.prepopulate_from:
+ t.append('document.getElementById("id_%s").onkeyup = function() { var e = document.getElementById("id_%s"); if(e._changed) { e.value = URLify(%s, %s);} } ' % (f, field.name, add_values, field.maxlength) )
+ return ''.join(t)
+auto_populated_field_script = simple_tag(auto_populated_field_script)
-def do_submit_row(parser, token):
- return SubmitRowNode()
-
+#@simple_tag
+def filter_interface_script_maybe(bound_field):
+ f = bound_field.field
+ if f.rel and isinstance(f.rel, meta.ManyToMany) and f.rel.filter_interface:
+ return '\n' % (f.name, f.verbose_name, f.rel.filter_interface-1, ADMIN_MEDIA_PREFIX)
+ else:
+ return ''
+filter_interface_script_maybe = simple_tag(filter_interface_script_maybe)
def do_one_arg_tag(node_factory, parser,token):
tokens = token.contents.split()
@@ -251,14 +202,8 @@ def do_one_arg_tag(node_factory, parser,token):
one_arg_tag_nodes = [
- IncludeAdminScriptNode,
- AdminFieldBoundNode,
- FieldLabelNode,
FieldWidgetNode,
- OutputAllNode,
EditInlineNode,
- AutoPopulatedFieldScriptNode,
- FilterInterfaceScriptMaybeNode,
]
@@ -267,9 +212,39 @@ def register_one_arg_tag(node):
parse_func = curry(do_one_arg_tag, node)
template.register_tag(tag_name, parse_func)
-
-
for node in one_arg_tag_nodes:
register_one_arg_tag(node)
-template.register_tag('submit_row', do_submit_row )
+
+#@inclusion_tag('admin_field', takes_context=True)
+def admin_field_bound(context, argument_val):
+ if (isinstance(argument_val, list)):
+ bound_fields = argument_val
+ else:
+ bound_fields = [argument_val]
+ add = context['add']
+ change = context['change']
+
+ class_names = ['form-row']
+ for bound_field in bound_fields:
+ for f in bound_field.form_fields:
+ if f.errors():
+ class_names.append('errors')
+ break
+
+ # Assumes BooleanFields won't be stacked next to each other!
+ if isinstance(bound_fields[0].field, meta.BooleanField):
+ class_names.append('checkbox-row')
+
+ return {
+ 'add' : context['add'],
+ 'change' : context['change'],
+ 'bound_fields' : bound_fields,
+ 'class_names' : " ".join(class_names)
+ }
+
+
+afbdec = inclusion_tag('admin_field', takes_context=True)
+admin_field_bound = afbdec(admin_field_bound)
+
+