Ticket #911: django-template-scoping.diff
File django-template-scoping.diff, 90.7 KB (added by , 19 years ago) |
---|
-
django/contrib/markup/templatetags/markup.py
=== django/contrib/markup/templatetags/markup.py ==================================================================
16 16 17 17 from django.core import template 18 18 19 def textile(value, _): 19 register = template.Library() 20 21 def textile(value): 20 22 try: 21 23 import textile 22 24 except ImportError: … … 24 26 else: 25 27 return textile.textile(value) 26 28 27 def markdown(value , _):29 def markdown(value): 28 30 try: 29 31 import markdown 30 32 except ImportError: … … 32 34 else: 33 35 return markdown.markdown(value) 34 36 35 def restructuredtext(value , _):37 def restructuredtext(value): 36 38 try: 37 39 from docutils.core import publish_parts 38 40 except ImportError: … … 41 43 parts = publish_parts(source=value, writer_name="html4css1") 42 44 return parts["fragment"] 43 45 44 template.register_filter("textile", textile, False)45 template.register_filter("markdown", markdown, False)46 template.register_filter("restructuredtext", restructuredtext, False)47 No newline at end of file 46 register.filter(textile) 47 register.filter(markdown) 48 register.filter(restructuredtext) 49 No newline at end of file -
django/contrib/comments/templatetags/comments.py
=== django/contrib/comments/templatetags/comments.py ==================================================================
6 6 from django.models.core import contenttypes 7 7 import re 8 8 9 register = template.Library() 10 9 11 COMMENT_FORM = ''' 10 12 {% load i18n %} 11 13 {% if display_form %} … … 360 362 return CommentListNode(package, module, var_name, obj_id, tokens[5], self.free, ordering) 361 363 362 364 # registration comments 363 template.register_tag('get_comment_list',DoGetCommentList(False))364 template.register_tag('comment_form', DoCommentForm(False))365 template.register_tag('get_comment_count',DoCommentCount(False))365 register.tag('get_comment_list',DoGetCommentList(False)) 366 register.tag('comment_form', DoCommentForm(False)) 367 register.tag('get_comment_count',DoCommentCount(False)) 366 368 # free comments 367 template.register_tag('get_free_comment_list', DoGetCommentList(True))368 template.register_tag('free_comment_form', DoCommentForm(True))369 template.register_tag('get_free_comment_count', DoCommentCount(True))369 register.tag('get_free_comment_list', DoGetCommentList(True)) 370 register.tag('free_comment_form', DoCommentForm(True)) 371 register.tag('get_free_comment_count', DoCommentCount(True)) -
django/contrib/admin/templatetags/adminmedia.py
=== django/contrib/admin/templatetags/adminmedia.py ==================================================================
1 from django.core.template.decorators import simple_tag 1 from django.core.template import Library 2 register = Library() 2 3 3 4 def admin_media_prefix(): 4 5 try: … … 6 7 except ImportError: 7 8 return '' 8 9 return ADMIN_MEDIA_PREFIX 9 admin_media_prefix = simple_tag(admin_media_prefix) 10 admin_media_prefix = register.simple_tag(admin_media_prefix) 11 No newline at end of file -
django/contrib/admin/templatetags/admin_modify.py
=== django/contrib/admin/templatetags/admin_modify.py ==================================================================
2 2 from django.utils.html import escape 3 3 from django.utils.text import capfirst 4 4 from django.utils.functional import curry 5 from django.core.template.decorators import simple_tag, inclusion_tag6 5 from django.contrib.admin.views.main import AdminBoundField 7 6 from django.core.meta.fields import BoundField, Field 8 7 from django.core.meta import BoundRelatedObject, TABULAR, STACKED 9 8 from django.conf.settings import ADMIN_MEDIA_PREFIX 10 9 import re 11 10 11 register = template.Library() 12 12 13 word_re = re.compile('[A-Z][a-z]+') 13 14 14 15 def class_name_to_underscored(name): 15 16 return '_'.join([s.lower() for s in word_re.findall(name)[:-1]]) 16 17 17 #@ simple_tag18 #@register.simple_tag 18 19 def include_admin_script(script_path): 19 20 return '<script type="text/javascript" src="%s%s"></script>' % (ADMIN_MEDIA_PREFIX, script_path) 20 include_admin_script = simple_tag(include_admin_script)21 include_admin_script = register.simple_tag(include_admin_script) 21 22 22 #@ inclusion_tag('admin/submit_line', takes_context=True)23 #@register.inclusion_tag('admin/submit_line', takes_context=True) 23 24 def submit_row(context, bound_manipulator): 24 25 change = context['change'] 25 26 add = context['add'] … … 36 37 'show_save_and_continue': not is_popup, 37 38 'show_save': True 38 39 } 39 submit_row = inclusion_tag('admin/submit_line', takes_context=True)(submit_row)40 submit_row = register.inclusion_tag('admin/submit_line', takes_context=True)(submit_row) 40 41 41 #@ simple_tag42 #@register.simple_tag 42 43 def field_label(bound_field): 43 44 class_names = [] 44 45 if isinstance(bound_field.field, meta.BooleanField): … … 53 54 class_str = class_names and ' class="%s"' % ' '.join(class_names) or '' 54 55 return '<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \ 55 56 capfirst(bound_field.field.verbose_name), colon) 56 field_label = simple_tag(field_label)57 field_label = register.simple_tag(field_label) 57 58 58 59 class FieldWidgetNode(template.Node): 59 60 nodelists = {} … … 170 171 context.pop() 171 172 return output 172 173 173 #@ simple_tag174 #@register.simple_tag 174 175 def output_all(form_fields): 175 176 return ''.join([str(f) for f in form_fields]) 176 output_all = simple_tag(output_all)177 output_all = register.simple_tag(output_all) 177 178 178 #@ simple_tag179 #@register.simple_tag 179 180 def auto_populated_field_script(auto_pop_fields, change = False): 180 181 for field in auto_pop_fields: 181 182 t = [] … … 191 192 ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % ( 192 193 f, field.name, add_values, field.maxlength)) 193 194 return ''.join(t) 194 auto_populated_field_script = simple_tag(auto_populated_field_script)195 auto_populated_field_script = register.simple_tag(auto_populated_field_script) 195 196 196 #@ simple_tag197 #@register.simple_tag 197 198 def filter_interface_script_maybe(bound_field): 198 199 f = bound_field.field 199 200 if f.rel and isinstance(f.rel, meta.ManyToMany) and f.rel.filter_interface: … … 202 203 f.name, f.verbose_name, f.rel.filter_interface-1, ADMIN_MEDIA_PREFIX) 203 204 else: 204 205 return '' 205 filter_interface_script_maybe = simple_tag(filter_interface_script_maybe)206 filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe) 206 207 207 208 def do_one_arg_tag(node_factory, parser,token): 208 209 tokens = token.contents.split() … … 213 214 def register_one_arg_tag(node): 214 215 tag_name = class_name_to_underscored(node.__name__) 215 216 parse_func = curry(do_one_arg_tag, node) 216 template.register_tag(tag_name, parse_func)217 register.tag(tag_name, parse_func) 217 218 218 219 one_arg_tag_nodes = ( 219 220 FieldWidgetNode, … … 223 224 for node in one_arg_tag_nodes: 224 225 register_one_arg_tag(node) 225 226 226 #@ inclusion_tag('admin/field_line', takes_context=True)227 #@register.inclusion_tag('admin/field_line', takes_context=True) 227 228 def admin_field_line(context, argument_val): 228 229 if (isinstance(argument_val, BoundField)): 229 230 bound_fields = [argument_val] … … 249 250 'bound_fields': bound_fields, 250 251 'class_names': " ".join(class_names), 251 252 } 252 admin_field_line = inclusion_tag('admin/field_line', takes_context=True)(admin_field_line)253 admin_field_line = register.inclusion_tag('admin/field_line', takes_context=True)(admin_field_line) 253 254 254 #@ simple_tag255 #@register.simple_tag 255 256 def object_pk(bound_manip, ordered_obj): 256 257 return bound_manip.get_ordered_object_pk(ordered_obj) 257 258 258 object_pk = simple_tag(object_pk)259 object_pk = register.simple_tag(object_pk) -
django/contrib/admin/templatetags/log.py
=== django/contrib/admin/templatetags/log.py ==================================================================
1 1 from django.models.admin import log 2 2 from django.core import template 3 3 4 register = template.Library() 5 4 6 class AdminLogNode(template.Node): 5 7 def __init__(self, limit, varname, user): 6 8 self.limit, self.varname, self.user = limit, varname, user … … 48 50 raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user'" % self.tag_name 49 51 return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(len(tokens) > 5 and tokens[5] or None)) 50 52 51 template.register_tag('get_admin_log', DoGetAdminLog('get_admin_log'))53 register.tag('get_admin_log', DoGetAdminLog('get_admin_log')) -
django/contrib/admin/templatetags/admin_list.py
=== django/contrib/admin/templatetags/admin_list.py ==================================================================
3 3 from django.contrib.admin.views.main import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE, MONTHS 4 4 from django.core import meta, template 5 5 from django.core.exceptions import ObjectDoesNotExist 6 from django.core.template.decorators import simple_tag, inclusion_tag7 6 from django.utils import dateformat 8 7 from django.utils.html import strip_tags, escape 9 8 from django.utils.text import capfirst 10 9 from django.utils.translation import get_date_formats 11 10 from django.conf.settings import ADMIN_MEDIA_PREFIX 11 from django.core.template import Library 12 12 13 register = Library() 14 13 15 DOT = '.' 14 16 15 #@ simple_tag17 #@register.simple_tag 16 18 def paginator_number(cl,i): 17 19 if i == DOT: 18 20 return '... ' … … 20 22 return '<span class="this-page">%d</span> ' % (i+1) 21 23 else: 22 24 return '<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1) 23 paginator_number = simple_tag(paginator_number)25 paginator_number = register.simple_tag(paginator_number) 24 26 25 #@ inclusion_tag('admin/pagination')27 #@register.inclusion_tag('admin/pagination') 26 28 def pagination(cl): 27 29 paginator, page_num = cl.paginator, cl.page_num 28 30 … … 64 66 'ALL_VAR': ALL_VAR, 65 67 '1': 1, 66 68 } 67 pagination = inclusion_tag('admin/pagination')(pagination)69 pagination = register.inclusion_tag('admin/pagination')(pagination) 68 70 69 71 def result_headers(cl): 70 72 lookup_opts = cl.lookup_opts … … 177 179 for res in cl.result_list: 178 180 yield list(items_for_result(cl,res)) 179 181 180 #@ inclusion_tag("admin/change_list_results")182 #@register.inclusion_tag("admin/change_list_results") 181 183 def result_list(cl): 182 184 res = list(results(cl)) 183 185 return {'cl': cl, 184 186 'result_headers': list(result_headers(cl)), 185 187 'results': list(results(cl))} 186 result_list = inclusion_tag("admin/change_list_results")(result_list)188 result_list = register.inclusion_tag("admin/change_list_results")(result_list) 187 189 188 #@ inclusion_tag("admin/date_hierarchy")190 #@register.inclusion_tag("admin/date_hierarchy") 189 191 def date_hierarchy(cl): 190 192 lookup_opts, params, lookup_params, lookup_mod = \ 191 193 cl.lookup_opts, cl.params, cl.lookup_params, cl.lookup_mod … … 256 258 'title': year.year 257 259 } for year in years ] 258 260 } 259 date_hierarchy = inclusion_tag('admin/date_hierarchy')(date_hierarchy)261 date_hierarchy = register.inclusion_tag('admin/date_hierarchy')(date_hierarchy) 260 262 261 #@ inclusion_tag('admin/search_form')263 #@register.inclusion_tag('admin/search_form') 262 264 def search_form(cl): 263 265 return { 264 266 'cl': cl, 265 267 'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field, 266 268 'search_var': SEARCH_VAR 267 269 } 268 search_form = inclusion_tag('admin/search_form')(search_form)270 search_form = register.inclusion_tag('admin/search_form')(search_form) 269 271 270 #@ inclusion_tag('admin/filter')272 #@register.inclusion_tag('admin/filter') 271 273 def filter(cl, spec): 272 274 return {'title': spec.title(), 'choices' : list(spec.choices(cl))} 273 filter = inclusion_tag('admin/filter')(filter)275 filter = register.inclusion_tag('admin/filter')(filter) 274 276 275 #@ inclusion_tag('admin/filters')277 #@register.inclusion_tag('admin/filters') 276 278 def filters(cl): 277 279 return {'cl': cl} 278 filters = inclusion_tag('admin/filters')(filters)280 filters = register.inclusion_tag('admin/filters')(filters) -
django/contrib/admin/templatetags/adminapplist.py
=== django/contrib/admin/templatetags/adminapplist.py ==================================================================
1 1 from django.core import template 2 2 3 register = template.Library() 4 3 5 class AdminApplistNode(template.Node): 4 6 def __init__(self, varname): 5 7 self.varname = varname … … 54 56 raise template.TemplateSyntaxError, "First argument to '%s' tag must be 'as'" % tokens[0] 55 57 return AdminApplistNode(tokens[2]) 56 58 57 template.register_tag('get_admin_app_list', get_admin_app_list)59 register.tag('get_admin_app_list', get_admin_app_list) -
django/contrib/admin/views/template.py
=== django/contrib/admin/views/template.py ==================================================================
55 55 node = loader.do_extends(parser, token) 56 56 node.template_dirs = settings_module.TEMPLATE_DIRS 57 57 return node 58 template.register_tag('extends', new_do_extends) 58 register = template.Library() 59 register.tag('extends', new_do_extends) 60 template.builtins.append(register) 59 61 60 62 # now validate the template using the new template dirs 61 63 # making sure to reset the extends function in any case … … 65 67 tmpl.render(template.Context({})) 66 68 except template.TemplateSyntaxError, e: 67 69 error = e 68 template. register_tag('extends', loader.do_extends)70 template.builtins.remove(register) 69 71 if error: 70 72 raise validators.ValidationError, e.args -
django/contrib/admin/templates/widget/file.html
=== django/contrib/admin/templates/widget/file.html ==================================================================
1 {% if bound_field.original_value %}1 {% load admin_modify %}{% if bound_field.original_value %} 2 2 Currently: <a href="{{ bound_field.original_url }}" > {{ bound_field.original_value }} </a><br /> 3 3 Change: {% output_all bound_field.form_fields %} 4 4 {% else %} {% output_all bound_field.form_fields %} {% endif %} -
django/contrib/admin/templates/widget/default.html
=== django/contrib/admin/templates/widget/default.html ==================================================================
1 {% output_all bound_field.form_fields %}1 {% load admin_modify %}{% output_all bound_field.form_fields %} -
django/contrib/admin/templates/widget/foreign.html
=== django/contrib/admin/templates/widget/foreign.html ==================================================================
1 {% load admin_modify adminmedia %} 1 2 {% output_all bound_field.form_fields %} 2 3 {% if bound_field.raw_id_admin %} 3 4 <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/" class="related-lookup" id="lookup_{{bound_field.element_id}}" onclick="return showRelatedObjectLookupPopup(this);"> <img src="{% admin_media_prefix %}img/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a> … … 4 5 {% else %} 5 6 {% if bound_field.needs_add_label %} 6 7 <a href="../../../{{ bound_field.field.rel.to.app_label }}/{{ bound_field.field.rel.to.module_name }}/add/" class="add-another" id="add_{{ bound_field.element_id}}" onclick="return showAddAnotherPopup(this);"> <img src="{% admin_media_prefix %}img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a> 7 {% endif %} 8 {% endif %}{% endif %} -
django/contrib/admin/templates/admin/change_list.html
=== django/contrib/admin/templates/admin/change_list.html ==================================================================
1 {% load admin_list %} 2 {% load i18n %} 1 {% load adminmedia admin_list i18n %} 3 2 {% extends "admin/base_site" %} 4 3 {% block bodyclass %}change-list{% endblock %} 5 4 {% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> › {{ cl.opts.verbose_name_plural|capfirst }} </div>{% endblock %}{% endif %} -
django/contrib/admin/templates/admin/edit_inline_stacked.html
=== django/contrib/admin/templates/admin/edit_inline_stacked.html ==================================================================
1 {% load admin_modify %} 1 2 <fieldset class="module aligned"> 2 3 {% for fcw in bound_related_object.form_field_collection_wrappers %} 3 4 <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }} #{{ forloop.counter }}</h2> -
django/contrib/admin/templates/admin/filter.html
=== django/contrib/admin/templates/admin/filter.html ==================================================================
1 {% load i18n %} 1 2 <h3>{% blocktrans %} By {{ title }} {% endblocktrans %}</h3> 2 3 <ul> 3 4 {% for choice in choices %} -
django/contrib/admin/templates/admin/search_form.html
=== django/contrib/admin/templates/admin/search_form.html ==================================================================
1 {% load adminmedia %} 1 2 {% if cl.lookup_opts.admin.search_fields %} 2 3 <div id="toolbar"><form id="changelist-search" action="" method="get"> 3 4 <label><img src="{% admin_media_prefix %}img/admin/icon_searchbox.png" /></label> -
django/contrib/admin/templates/admin/pagination.html
=== django/contrib/admin/templates/admin/pagination.html ==================================================================
1 {% load admin_list %} 1 2 <p class="paginator"> 2 3 {% if pagination_required %} 3 4 {% for i in page_range %} -
django/contrib/admin/templates/admin/field_line.html
=== django/contrib/admin/templates/admin/field_line.html ==================================================================
1 {% load admin_modify %} 1 2 <div class="{{ class_names }}" > 2 3 {% for bound_field in bound_fields %}{{ bound_field.html_error_list }}{% endfor %} 3 4 {% for bound_field in bound_fields %} -
django/contrib/admin/templates/admin/edit_inline_tabular.html
=== django/contrib/admin/templates/admin/edit_inline_tabular.html ==================================================================
1 {% load admin_modify %} 1 2 <fieldset class="module"> 2 3 <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table> 3 4 <thead><tr> -
django/contrib/admin/templates/admin/filters.html
=== django/contrib/admin/templates/admin/filters.html ==================================================================
1 {% load admin_list %} 1 2 {% if cl.has_filters %}<div id="changelist-filter"> 2 3 <h2>Filter</h2> 3 4 {% for spec in cl.filter_specs %} -
django/contrib/admin/templates/admin/change_form.html
=== django/contrib/admin/templates/admin/change_form.html ==================================================================
1 1 {% extends "admin/base_site" %} 2 {% load i18n %} 3 {% load admin_modify %} 4 {% load adminmedia %} 2 {% load i18n admin_modify adminmedia %} 5 3 {% block extrahead %} 6 4 {% for js in bound_manipulator.javascript_imports %}{% include_admin_script js %}{% endfor %} 7 5 {% endblock %} -
django/core/template/defaultfilters.py
=== django/core/template/defaultfilters.py ==================================================================
1 1 "Default variable filters" 2 2 3 from django.core.template import re gister_filter, resolve_variable3 from django.core.template import resolve_variable, Library 4 4 import re 5 5 import random as random_module 6 6 7 register = Library() 7 8 ################### 8 9 # STRINGS # 9 10 ################### 10 11 11 def addslashes(value, _): 12 13 def addslashes(value): 12 14 "Adds slashes - useful for passing strings to JavaScript, for example." 13 15 return value.replace('"', '\\"').replace("'", "\\'") 14 16 15 def capfirst(value , _):17 def capfirst(value): 16 18 "Capitalizes the first character of the value" 17 19 value = str(value) 18 20 return value and value[0].upper() + value[1:] 19 21 20 def fix_ampersands(value , _):22 def fix_ampersands(value): 21 23 "Replaces ampersands with ``&`` entities" 22 24 from django.utils.html import fix_ampersands 23 25 return fix_ampersands(value) 24 26 25 def floatformat(text , _):27 def floatformat(text): 26 28 """ 27 29 Displays a floating point number as 34.2 (with one decimal place) -- but 28 30 only if there's a point to be displayed … … 37 39 else: 38 40 return '%d' % int(f) 39 41 40 def linenumbers(value , _):42 def linenumbers(value): 41 43 "Displays text with line numbers" 42 44 from django.utils.html import escape 43 45 lines = value.split('\n') … … 47 49 lines[i] = ("%0" + width + "d. %s") % (i + 1, escape(line)) 48 50 return '\n'.join(lines) 49 51 50 def lower(value , _):52 def lower(value): 51 53 "Converts a string into all lowercase" 52 54 return value.lower() 53 55 54 def make_list(value , _):56 def make_list(value): 55 57 """ 56 58 Returns the value turned into a list. For an integer, it's a list of 57 59 digits. For a string, it's a list of characters. 58 60 """ 59 61 return list(str(value)) 60 62 61 def slugify(value , _):63 def slugify(value): 62 64 "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens" 63 65 value = re.sub('[^\w\s-]', '', value).strip().lower() 64 66 return re.sub('\s+', '-', value) … … 77 79 except (ValueError, TypeError): 78 80 return "" 79 81 80 def title(value , _):82 def title(value): 81 83 "Converts a string into titlecase" 82 84 return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) 83 85 … … 96 98 value = str(value) 97 99 return truncate_words(value, length) 98 100 99 def upper(value , _):101 def upper(value): 100 102 "Converts a string into all uppercase" 101 103 return value.upper() 102 104 103 def urlencode(value , _):105 def urlencode(value): 104 106 "Escapes a value for use in a URL" 105 107 import urllib 106 108 return urllib.quote(value) 107 109 108 def urlize(value , _):110 def urlize(value): 109 111 "Converts URLs in plain text into clickable links" 110 112 from django.utils.html import urlize 111 113 return urlize(value, nofollow=True) … … 119 121 from django.utils.html import urlize 120 122 return urlize(value, trim_url_limit=int(limit), nofollow=True) 121 123 122 def wordcount(value , _):124 def wordcount(value): 123 125 "Returns the number of words" 124 126 return len(value.split()) 125 127 … … 160 162 # HTML STRINGS # 161 163 ################### 162 164 163 def escape(value , _):165 def escape(value): 164 166 "Escapes a string's HTML" 165 167 from django.utils.html import escape 166 168 return escape(value) 167 169 168 def linebreaks(value , _):170 def linebreaks(value): 169 171 "Converts newlines into <p> and <br />s" 170 172 from django.utils.html import linebreaks 171 173 return linebreaks(value) 172 174 173 def linebreaksbr(value , _):175 def linebreaksbr(value): 174 176 "Converts newlines into <br />s" 175 177 return value.replace('\n', '<br />') 176 178 … … 184 186 value = endtag_re.sub('', value) 185 187 return value 186 188 187 def striptags(value , _):189 def striptags(value): 188 190 "Strips all [X]HTML tags" 189 191 from django.utils.html import strip_tags 190 192 if not isinstance(value, basestring): … … 214 216 decorated.reverse() 215 217 return [item[1] for item in decorated] 216 218 217 def first(value , _):219 def first(value): 218 220 "Returns the first item in a list" 219 221 try: 220 222 return value[0] … … 228 230 except AttributeError: # fail silently but nicely 229 231 return value 230 232 231 def length(value , _):233 def length(value): 232 234 "Returns the length of the value - useful for lists" 233 235 return len(value) 234 236 … … 236 238 "Returns a boolean of whether the value's length is the argument" 237 239 return len(value) == int(arg) 238 240 239 def random(value , _):241 def random(value): 240 242 "Returns a random item from the list" 241 243 return random_module.choice(value) 242 244 … … 253 255 except (ValueError, TypeError): 254 256 return value # Fail silently. 255 257 256 def unordered_list(value , _):258 def unordered_list(value): 257 259 """ 258 260 Recursively takes a self-nested list and returns an HTML unordered list -- 259 261 WITHOUT opening and closing <ul> tags. … … 313 315 ################### 314 316 # DATES # 315 317 ################### 318 from django.conf.settings import DATE_FORMAT, TIME_FORMAT 316 319 317 def date(value, arg ):320 def date(value, arg = DATE_FORMAT): 318 321 "Formats a date according to the given format" 319 322 from django.utils.dateformat import format 320 323 return format(value, arg) 321 324 322 def time(value, arg ):325 def time(value, arg = TIME_FORMAT): 323 326 "Formats a time according to the given format" 324 327 from django.utils.dateformat import time_format 325 328 return time_format(value, arg) 326 329 327 def timesince(value , _):330 def timesince(value): 328 331 'Formats a date as the time since that date (i.e. "4 days, 6 hours")' 329 332 from django.utils.timesince import timesince 330 333 return timesince(value) … … 347 350 "Returns true if the value is devisible by the argument" 348 351 return int(value) % int(arg) == 0 349 352 350 def yesno(value, arg ):353 def yesno(value, arg=_("yes,no,maybe")): 351 354 """ 352 355 Given a string mapping values for true, false and (optionally) None, 353 356 returns one of those strings accoding to the value: … … 379 382 # MISC # 380 383 ################### 381 384 382 def filesizeformat(bytes , _):385 def filesizeformat(bytes): 383 386 """ 384 387 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102 385 388 bytes, etc). … … 393 396 return "%.1f MB" % (bytes / (1024 * 1024)) 394 397 return "%.1f GB" % (bytes / (1024 * 1024 * 1024)) 395 398 396 def pluralize(value , _):399 def pluralize(value): 397 400 "Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'" 398 401 try: 399 402 if int(value) != 1: … … 408 411 pass 409 412 return '' 410 413 411 def phone2numeric(value , _):414 def phone2numeric(value): 412 415 "Takes a phone number and converts it in to its numerical equivalent" 413 416 from django.utils.text import phone2numeric 414 417 return phone2numeric(value) 415 418 416 def pprint(value , _):419 def pprint(value): 417 420 "A wrapper around pprint.pprint -- for debugging, really" 418 421 from pprint import pformat 419 422 return pformat(value) 420 423 421 # Syntax: register_filter(name of filter, callback, has_argument) 422 register_filter('add', add, True) 423 register_filter('addslashes', addslashes, False) 424 register_filter('capfirst', capfirst, False) 425 register_filter('center', center, True) 426 register_filter('cut', cut, True) 427 register_filter('date', date, True) 428 register_filter('default', default, True) 429 register_filter('default_if_none', default_if_none, True) 430 register_filter('dictsort', dictsort, True) 431 register_filter('dictsortreversed', dictsortreversed, True) 432 register_filter('divisibleby', divisibleby, True) 433 register_filter('escape', escape, False) 434 register_filter('filesizeformat', filesizeformat, False) 435 register_filter('first', first, False) 436 register_filter('fix_ampersands', fix_ampersands, False) 437 register_filter('floatformat', floatformat, False) 438 register_filter('get_digit', get_digit, True) 439 register_filter('join', join, True) 440 register_filter('length', length, False) 441 register_filter('length_is', length_is, True) 442 register_filter('linebreaks', linebreaks, False) 443 register_filter('linebreaksbr', linebreaksbr, False) 444 register_filter('linenumbers', linenumbers, False) 445 register_filter('ljust', ljust, True) 446 register_filter('lower', lower, False) 447 register_filter('make_list', make_list, False) 448 register_filter('phone2numeric', phone2numeric, False) 449 register_filter('pluralize', pluralize, False) 450 register_filter('pprint', pprint, False) 451 register_filter('removetags', removetags, True) 452 register_filter('random', random, False) 453 register_filter('rjust', rjust, True) 454 register_filter('slice', slice_, True) 455 register_filter('slugify', slugify, False) 456 register_filter('stringformat', stringformat, True) 457 register_filter('striptags', striptags, False) 458 register_filter('time', time, True) 459 register_filter('timesince', timesince, False) 460 register_filter('title', title, False) 461 register_filter('truncatewords', truncatewords, True) 462 register_filter('unordered_list', unordered_list, False) 463 register_filter('upper', upper, False) 464 register_filter('urlencode', urlencode, False) 465 register_filter('urlize', urlize, False) 466 register_filter('urlizetrunc', urlizetrunc, True) 467 register_filter('wordcount', wordcount, False) 468 register_filter('wordwrap', wordwrap, True) 469 register_filter('yesno', yesno, True) 424 # Syntax: register.filter(name of filter, callback) 425 register.filter(add) 426 register.filter(addslashes) 427 register.filter(capfirst) 428 register.filter(center) 429 register.filter(cut) 430 register.filter(date) 431 register.filter(default) 432 register.filter(default_if_none) 433 register.filter(dictsort) 434 register.filter(dictsortreversed) 435 register.filter(divisibleby) 436 register.filter(escape) 437 register.filter(filesizeformat) 438 register.filter(first) 439 register.filter(fix_ampersands) 440 register.filter(floatformat) 441 register.filter(get_digit) 442 register.filter(join) 443 register.filter(length) 444 register.filter(length_is) 445 register.filter(linebreaks) 446 register.filter(linebreaksbr) 447 register.filter(linenumbers) 448 register.filter(ljust) 449 register.filter(lower) 450 register.filter(make_list) 451 register.filter(phone2numeric) 452 register.filter(pluralize) 453 register.filter(pprint) 454 register.filter(removetags) 455 register.filter(random) 456 register.filter(rjust) 457 register.filter(slice_) 458 register.filter(slugify) 459 register.filter(stringformat) 460 register.filter(striptags) 461 register.filter(time) 462 register.filter(timesince) 463 register.filter(title) 464 register.filter(truncatewords) 465 register.filter(unordered_list) 466 register.filter(upper) 467 register.filter(urlencode) 468 register.filter(urlize) 469 register.filter(urlizetrunc) 470 register.filter(wordcount) 471 register.filter(wordwrap) 472 register.filter(yesno) 473 No newline at end of file -
django/core/template/__init__.py
=== django/core/template/__init__.py ==================================================================
3 3 4 4 How it works: 5 5 6 The tokenize() function converts a template string (i.e., a string containing6 The Lexer.tokenize() function converts a template string (i.e., a string containing 7 7 markup with custom template tags) to tokens, which can be either plain text 8 8 (TOKEN_TEXT), variables (TOKEN_VAR) or block statements (TOKEN_BLOCK). 9 9 … … 55 55 '\n<html>\n\n</html>\n' 56 56 """ 57 57 import re 58 from inspect import getargspec 59 from django.utils.functional import curry 58 60 from django.conf.settings import DEFAULT_CHARSET, TEMPLATE_DEBUG 59 61 60 62 __all__ = ('Template','Context','compile_string') … … 82 84 tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 83 85 re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END))) 84 86 85 # global dict used by register_tag; maps custom tags to callback functions 86 registered_tags = {} 87 # global dictionary of libraries that have been loaded using get_library 88 libraries = {} 89 # global list of libraries to load by default for a new parser 90 builtins = [] 87 91 88 # global dict used by register_filter; maps custom filters to callback functions89 registered_filters = {}90 91 92 class TemplateSyntaxError(Exception): 92 93 pass 93 94 … … 105 106 "Any function raising this exception will be ignored by resolve_variable" 106 107 pass 107 108 109 class InvalidTemplateLibraryException(Exception): 110 pass 111 108 112 class Origin(object): 109 113 def __init__(self, name): 110 114 self.name = name … … 264 268 class Parser(object): 265 269 def __init__(self, tokens): 266 270 self.tokens = tokens 271 self.tags = {} 272 self.filters = {} 273 for lib in builtins: 274 self.add_library(lib) 267 275 268 276 def parse(self, parse_until=[]): 269 277 nodelist = self.create_nodelist() … … 274 282 elif token.token_type == TOKEN_VAR: 275 283 if not token.contents: 276 284 self.empty_variable(token) 277 var_node = self.create_variable_node(token.contents) 285 filter_expression = self.compile_filter(token.contents) 286 var_node = self.create_variable_node(filter_expression) 278 287 self.extend_nodelist(nodelist, var_node,token) 279 288 elif token.token_type == TOKEN_BLOCK: 280 289 if token.contents in parse_until: … … 288 297 # execute callback function for this tag and append resulting node 289 298 self.enter_command(command, token) 290 299 try: 291 compile_func = registered_tags[command]300 compile_func = self.tags[command] 292 301 except KeyError: 293 302 self.invalid_block_tag(token, command) 294 303 try: … … 302 311 self.unclosed_block_tag(parse_until) 303 312 return nodelist 304 313 305 def create_variable_node(self, contents):306 return VariableNode( contents)314 def create_variable_node(self, filter_expression): 315 return VariableNode(filter_expression) 307 316 308 317 def create_nodelist(self): 309 318 return NodeList() … … 344 353 def delete_first_token(self): 345 354 del self.tokens[0] 346 355 356 def add_library(self, lib): 357 self.tags.update(lib.tags) 358 self.filters.update(lib.filters) 359 360 def compile_filter(self,token): 361 "Convenient wrapper for FilterExpression" 362 return FilterExpression(token, self) 363 364 def find_filter(self, filter_name): 365 if self.filters.has_key(filter_name): 366 return self.filters[filter_name] 367 else: 368 raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name 369 347 370 class DebugParser(Parser): 348 371 def __init__(self, lexer): 349 372 super(DebugParser, self).__init__(lexer) … … 483 506 (?:%(arg_sep)s 484 507 (?: 485 508 %(i18n_open)s"(?P<i18n_arg>%(str)s)"%(i18n_close)s| 486 "(?P<arg>%(str)s)" 509 "(?P<constant_arg>%(str)s)"| 510 (?P<var_arg>[%(var_chars)s]+) 487 511 ) 488 512 )? 489 513 )""" % { … … 498 522 filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "") 499 523 filter_re = re.compile(filter_raw_string) 500 524 501 class Filter Parser(object):525 class FilterExpression(object): 502 526 """ 503 527 Parses a variable token and its optional filters (all as a single string), 504 528 and return a list of tuples of the filter name and arguments. … … 513 537 This class should never be instantiated outside of the 514 538 get_filters_from_token helper function. 515 539 """ 516 def __init__(self, token): 540 def __init__(self, token, parser): 541 self.token = token 517 542 matches = filter_re.finditer(token) 518 543 var = None 519 544 filters = [] … … 536 561 raise TemplateSyntaxError, "Variables and attributes may not begin with underscores: '%s'" % var 537 562 else: 538 563 filter_name = match.group("filter_name") 539 arg, i18n_arg = match.group("arg","i18n_arg") 564 args = [] 565 constant_arg, i18n_arg, var_arg = match.group("constant_arg","i18n_arg", "var_arg") 540 566 if i18n_arg: 541 arg =_(i18n_arg.replace('\\', '')) 542 if arg: 543 arg = arg.replace('\\', '') 544 if not registered_filters.has_key(filter_name): 545 raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name 546 if registered_filters[filter_name][1] == True and arg is None: 547 raise TemplateSyntaxError, "Filter '%s' requires an argument" % filter_name 548 if registered_filters[filter_name][1] == False and arg is not None: 549 raise TemplateSyntaxError, "Filter '%s' should not have an argument (argument is %r)" % (filter_name, arg) 550 filters.append( (filter_name,arg) ) 567 args.append((False, _(i18n_arg.replace('\\', '')))) 568 elif constant_arg: 569 args.append((False, constant_arg.replace('\\', ''))) 570 elif var_arg: 571 args.append((True, var_arg)) 572 573 filter_func = parser.find_filter(filter_name) 574 #if needs_arg == True and arg is None: 575 # raise TemplateSyntaxError, "Filter '%s' requires an argument" % filter_name 576 #if needs_arg == False and arg is not None: 577 # raise TemplateSyntaxError, "Filter '%s' should not have an argument (argument is %r)" % (filter_name, arg) 578 579 self.args_check(filter_name,filter_func, args) 580 filters.append( (filter_func,args)) 551 581 upto = match.end() 552 582 if upto != len(token): 553 583 raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] 554 584 self.var , self.filters = var, filters 555 585 556 def get_filters_from_token(token): 557 "Convenient wrapper for FilterParser" 558 p = FilterParser(token) 559 return (p.var, p.filters) 586 def resolve(self, context): 587 try: 588 obj = resolve_variable(self.var, context) 589 except VariableDoesNotExist: 590 obj = '' 591 for func, args in self.filters: 592 arg_vals = [] 593 for lookup, arg in args: 594 if not lookup: 595 arg_vals.append(arg) 596 else: 597 arg_vals.append(resolve_variable(arg, context)) 598 obj = func(obj, *arg_vals) 599 return obj 600 601 def args_check(name, func, provided): 602 provided = list(provided) 603 plen = len(provided) 604 (args, varargs, varkw, defaults) = getargspec(func) 605 # first argument is filter input 606 args.pop(0) 607 if defaults: 608 nondefs = args[:-len(defaults)] 609 else: 610 nondefs = args 611 # args without defaults must be provided 612 #print args, nondefs 613 try: 614 for arg in nondefs: 615 provided.pop(0) 616 except IndexError: 617 #Not enough 618 raise TemplateSyntaxError, "%s requires %d arguments, %d provided" % (name, len(nondefs), plen) 619 620 621 #defaults can be overridden 622 defaults = defaults and list(defaults) or [] 623 try: 624 for parg in provided: 625 defaults.pop(0) 626 except IndexError: 627 #Too many 628 raise TemplateSyntaxError, "%s requires %d arguments, %d provided" % (name, len(nondefs), plen) 629 630 return True 631 632 633 args_check = staticmethod(args_check) 634 635 def __str__(self): 636 return self.token 560 637 561 638 def resolve_variable(path, context): 562 639 """ … … 607 684 del bits[0] 608 685 return current 609 686 610 def resolve_variable_with_filters(var_string, context):611 """612 var_string is a full variable expression with optional filters, like:613 a.b.c|lower|date:"y/m/d"614 This function resolves the variable in the context, applies all filters and615 returns the object.616 """617 var, filters = get_filters_from_token(var_string)618 try:619 obj = resolve_variable(var, context)620 except VariableDoesNotExist:621 obj = ''622 for name, arg in filters:623 obj = registered_filters[name][0](obj, arg)624 return obj625 626 687 class Node: 627 688 def render(self, context): 628 689 "Return the node rendered as a string" … … 687 748 return self.s 688 749 689 750 class VariableNode(Node): 690 def __init__(self, var_string):691 self. var_string = var_string751 def __init__(self, filter_expression): 752 self.filter_expression = filter_expression 692 753 693 754 def __repr__(self): 694 return "<Variable Node: %s>" % self. var_string755 return "<Variable Node: %s>" % self.filter_expression 695 756 696 757 def encode_output(self, output): 697 758 # Check type so that we don't run str() on a Unicode object … … 703 764 return output 704 765 705 766 def render(self, context): 706 output = resolve_variable_with_filters(self.var_string,context)767 output = self.filter_expression.resolve(context) 707 768 return self.encode_output(output) 708 769 709 770 class DebugVariableNode(VariableNode): 710 771 def render(self, context): 711 772 try: 712 output = resolve_variable_with_filters(self.var_string,context)773 output = self.filter_expression.resolve(context) 713 774 except TemplateSyntaxError, e: 714 775 if not hasattr(e, 'source'): 715 776 e.source = self.source 716 777 raise 717 778 return self.encode_output(output) 718 779 719 def register_tag(token_command, callback_function): 720 registered_tags[token_command] = callback_function 780 def generic_tag_compiler(params, defaults, name, node_class, parser, token): 781 "Returns a template.Node subclass." 782 bits = token.contents.split()[1:] 783 bmax = len(params) 784 def_len = defaults and len(defaults) or 0 785 bmin = bmax - def_len 786 if(len(bits) < bmin or len(bits) > bmax): 787 if bmin == bmax: 788 message = "%s takes %s arguments" % (name, bmin) 789 else: 790 message = "%s takes between %s and %s arguments" % (name, bmin, bmax) 791 raise TemplateSyntaxError, message 792 return node_class(bits) 721 793 722 def unregister_tag(token_command): 723 del registered_tags[token_command] 794 class Library(object): 795 def __init__(self): 796 self.filters = {} 797 self.tags = {} 798 799 def tag(self, name = None, compile_function = None): 800 if name == None and compile_function == None: 801 #@register.tag() 802 return self.tag_function 803 elif name != None and compile_function == None: 804 if(callable(name)): 805 #@register.tag 806 return self.tag_function(name) 807 else: 808 #@register.tag('somename') or @register.tag(name='somename') 809 def dec(func): 810 return self.tag(name, func) 811 return dec 812 elif name != None and compile_function != None: 813 #register.tag('somename', somefunc) 814 self.tags[name] = compile_function 815 return compile_function 816 else: 817 raise InvalidTemplateLibraryException, "Unsupported arguments to Library.tag,(%r, %r)", (name, compile_function) 818 819 def tag_function(self,func): 820 self.tags[func.__name__] = func 821 return func 822 823 def filter(self, name = None, filter_func = None): 824 if name == None and filter_func == None: 825 #@register.filter() 826 return self.filter_function 827 elif filter_func == None: 828 if(callable(name)): 829 #@register.filter 830 return self.filter_function(name) 831 else: 832 #@register.filter('somename') or @register.filter(name='somename') 833 def dec(func): 834 return self.filter(name, func) 835 return dec 836 elif name != None and filter_func != None: 837 #register.filter('somename', somefunc) 838 self.filters[name] = filter_func 839 else: 840 raise InvalidTemplateLibraryException, "Unsupported arguments to Library.filter,(%r, %r, %r)", (name, compile_function, has_arg) 724 841 725 def register_filter(filter_name, callback_function, has_arg): 726 registered_filters[filter_name] = (callback_function, has_arg) 842 def filter_function(self, func): 843 self.filters[func.__name__] = func 844 return func 845 846 def simple_tag(self,func): 847 (params, xx, xxx, defaults) = getargspec(func) 848 849 class SimpleNode(Node): 850 def __init__(self, vars_to_resolve): 851 self.vars_to_resolve = vars_to_resolve 852 853 def render(self, context): 854 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 855 return func(*resolved_vars) 856 857 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode) 858 compile_func.__doc__ = func.__doc__ 859 self.tag(func.__name__, compile_func) 860 return func 727 861 728 def unregister_filter(filter_name): 729 del registered_filters[filter_name] 862 def inclusion_tag(self, file_name, context_class=Context, takes_context=False): 863 def dec(func): 864 (params, xx, xxx, defaults) = getargspec(func) 865 if takes_context: 866 if params[0] == 'context': 867 params = params[1:] 868 else: 869 raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'" 870 871 class InclusionNode(Node): 872 def __init__(self, vars_to_resolve): 873 self.vars_to_resolve = vars_to_resolve 874 875 def render(self, context): 876 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 877 if takes_context: 878 args = [context] + resolved_vars 879 else: 880 args = resolved_vars 881 882 dict = func(*args) 883 884 if not getattr(self, 'nodelist', False): 885 from django.core.template_loader import get_template 886 t = get_template(file_name) 887 self.nodelist = t.nodelist 888 return self.nodelist.render(context_class(dict)) 889 890 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode) 891 compile_func.__doc__ = func.__doc__ 892 self.tag(func.__name__, compile_func) 893 return func 894 return dec 730 895 731 import defaulttags 732 import defaultfilters 896 def get_library(module_name): 897 lib = libraries.get(module_name, None) 898 if not lib: 899 try: 900 mod = __import__(module_name, '', '', ['']) 901 except ImportError, e: 902 raise InvalidTemplateLibraryException, \ 903 "Could not load template library from %s, %s" % (module_name, e) 904 for k, v in mod.__dict__.items(): 905 if isinstance(v, Library): 906 lib = v 907 libraries[module_name] = lib 908 break 909 if not lib: 910 raise InvalidTemplateLibraryException, \ 911 "Template library %s does not have a Library member" % module_name 912 return lib 913 914 def add_to_builtins(module_name): 915 builtins.append(get_library(module_name)) 916 917 add_to_builtins('django.core.template.defaulttags') 918 add_to_builtins('django.core.template.defaultfilters') 919 No newline at end of file -
django/core/template/defaulttags.py
=== django/core/template/defaulttags.py ==================================================================
1 1 "Default tags used by the template system, available to all templates." 2 2 3 from django.core.template import Node, NodeList, Template, Context, resolve_variable, resolve_variable_with_filters, get_filters_from_token, registered_filters 4 from django.core.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, register_tag 3 from django.core.template import Node, NodeList, Template, Context, resolve_variable 4 from django.core.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END 5 from django.core.template import get_library, Library, InvalidTemplateLibraryException 5 6 import sys 6 7 8 register = Library() 9 7 10 class CommentNode(Node): 8 11 def render(self, context): 9 12 return '' … … 27 30 return ''.join(output) 28 31 29 32 class FilterNode(Node): 30 def __init__(self, filter s, nodelist):31 self.filter s, self.nodelist = filters, nodelist33 def __init__(self, filter_expr, nodelist): 34 self.filter_expr, self.nodelist = filter_expr, nodelist 32 35 33 36 def render(self, context): 34 37 output = self.nodelist.render(context) 35 38 # apply filters 36 for f in self.filters: 37 output = registered_filters[f[0]][0](output, f[1]) 38 return output 39 return filter_expr.resolve(Context({'var': output})) 39 40 40 41 class FirstOfNode(Node): 41 42 def __init__(self, vars): … … 81 82 parentloop = {} 82 83 context.push() 83 84 try: 84 values = resolve_variable_with_filters(self.sequence,context)85 values = self.sequence.resolve(context) 85 86 except VariableDoesNotExist: 86 87 values = [] 87 88 if values is None: … … 147 148 return self.nodelist_false.render(context) 148 149 149 150 class IfNode(Node): 150 def __init__(self, bool vars, nodelist_true, nodelist_false):151 self.bool vars = boolvars151 def __init__(self, bool_exprs, nodelist_true, nodelist_false): 152 self.bool_exprs = bool_exprs 152 153 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false 153 154 154 155 def __repr__(self): … … 169 170 return nodes 170 171 171 172 def render(self, context): 172 for ifnot, bool var in self.boolvars:173 for ifnot, bool_expr in self.bool_exprs: 173 174 try: 174 value = resolve_variable_with_filters(boolvar,context)175 value = bool_expr.resolve(context) 175 176 except VariableDoesNotExist: 176 177 value = None 177 178 if (value and not ifnot) or (ifnot and not value): … … 179 180 return self.nodelist_false.render(context) 180 181 181 182 class RegroupNode(Node): 182 def __init__(self, target _var, expression, var_name):183 self.target _var, self.expression = target_var, expression183 def __init__(self, target, expression, var_name): 184 self.target, self.expression = target, expression 184 185 self.var_name = var_name 185 186 186 187 def render(self, context): 187 obj_list = resolve_variable_with_filters(self.target_var,context)188 obj_list = self.target.resolve(context) 188 189 if obj_list == '': # target_var wasn't found in context; fail silently 189 190 context[self.var_name] = [] 190 191 return '' 191 192 output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} 192 193 for obj in obj_list: 193 grouper = resolve_variable_with_filters('var.%s' % self.expression, \ 194 Context({'var': obj})) 194 grouper = self.expression.resolve(Context({'var': obj})) 195 195 # TODO: Is this a sensible way to determine equality? 196 196 if output and repr(output[-1]['grouper']) == repr(grouper): 197 197 output[-1]['list'].append(obj) … … 236 236 return output 237 237 238 238 class LoadNode(Node): 239 def __init__(self, taglib):240 self.taglib = taglib241 242 def load_taglib(taglib):243 mod = __import__("django.templatetags.%s" % taglib.split('.')[-1], '', '', [''])244 reload(mod)245 return mod246 load_taglib = staticmethod(load_taglib)247 248 239 def render(self, context): 249 "Import the relevant module"250 try:251 self.__class__.load_taglib(self.taglib)252 except ImportError:253 pass # Fail silently for invalid loads.254 240 return '' 255 241 256 242 class NowNode(Node): … … 276 262 return self.mapping.get(self.tagtype, '') 277 263 278 264 class WidthRatioNode(Node): 279 def __init__(self, val_ var, max_var, max_width):280 self.val_ var = val_var281 self.max_ var = max_var265 def __init__(self, val_expr, max_expr, max_width): 266 self.val_expr = val_expr 267 self.max_expr = max_expr 282 268 self.max_width = max_width 283 269 284 270 def render(self, context): 285 271 try: 286 value = resolve_variable_with_filters(self.val_var,context)287 maxvalue = resolve_variable_with_filters(self.max_var,context)272 value = self.val_expr.resolve(context) 273 maxvalue = self.max_expr.resolve(context) 288 274 except VariableDoesNotExist: 289 275 return '' 290 276 try: … … 295 281 return '' 296 282 return str(int(round(ratio))) 297 283 298 def do_comment(parser, token): 284 #@register.tag 285 def comment(parser, token): 299 286 """ 300 287 Ignore everything between ``{% comment %}`` and ``{% endcomment %}`` 301 288 """ 302 289 nodelist = parser.parse(('endcomment',)) 303 290 parser.delete_first_token() 304 291 return CommentNode() 292 comment = register.tag(comment) 305 293 306 def do_cycle(parser, token): 294 #@register.tag 295 def cycle(parser, token): 307 296 """ 308 297 Cycle among the given strings each time this tag is encountered 309 298 … … 369 358 370 359 else: 371 360 raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args) 361 cycle = register.tag(cycle) 372 362 373 def do_debug(parser, token): 374 "Print a whole load of debugging information, including the context and imported modules" 375 return DebugNode() 376 363 #@register.tag(name="filter") 377 364 def do_filter(parser, token): 378 365 """ 379 366 Filter the contents of the blog through variable filters. … … 388 375 {% endfilter %} 389 376 """ 390 377 _, rest = token.contents.split(None, 1) 391 _, filters = get_filters_from_token('var|%s' % rest)378 filter_expr = parser.compile_filter("var|%s" % (rest)) 392 379 nodelist = parser.parse(('endfilter',)) 393 380 parser.delete_first_token() 394 return FilterNode(filters, nodelist) 381 return FilterNode(filter_expr, nodelist) 382 filter = register.tag("filter", do_filter) 395 383 396 def do_firstof(parser, token): 384 #@register.tag 385 def firstof(parser, token): 397 386 """ 398 387 Outputs the first variable passed that is not False. 399 388 … … 419 408 if len(bits) < 1: 420 409 raise TemplateSyntaxError, "'firstof' statement requires at least one argument" 421 410 return FirstOfNode(bits) 411 firstof = register.tag(firstof) 422 412 423 413 #@register.tag(name="for") 424 414 def do_for(parser, token): 425 415 """ 426 416 Loop over each item in an array. … … 462 452 if bits[2] != 'in': 463 453 raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents 464 454 loopvar = bits[1] 465 sequence = bits[3]455 sequence = parser.compile_filter(bits[3]) 466 456 reversed = (len(bits) == 5) 467 457 nodelist_loop = parser.parse(('endfor',)) 468 458 parser.delete_first_token() 469 459 return ForNode(loopvar, sequence, reversed, nodelist_loop) 460 do_for = register.tag("for", do_for) 470 461 471 462 def do_ifequal(parser, token, negate): 472 463 """ … … 497 488 nodelist_false = NodeList() 498 489 return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate) 499 490 491 #@register.tag 492 def ifequal(parser, token): 493 return do_ifequal(parser, token, False) 494 ifequal = register.tag(ifequal) 495 496 #@register.tag 497 def ifnotequal(parser, token): 498 return do_ifequal(parser, token, True) 499 ifnotequal = register.tag(ifnotequal) 500 501 #@register.tag(name="if") 500 502 def do_if(parser, token): 501 503 """ 502 504 The ``{% if %}`` tag evaluates a variable, and if that variable is "true" … … 554 556 not_, boolvar = boolpair.split() 555 557 if not_ != 'not': 556 558 raise TemplateSyntaxError, "Expected 'not' in if statement" 557 boolvars.append((True, boolvar))559 boolvars.append((True, parser.compile_filter(boolvar))) 558 560 else: 559 boolvars.append((False, boolpair))561 boolvars.append((False, parser.compile_filter(boolpair))) 560 562 nodelist_true = parser.parse(('else', 'endif')) 561 563 token = parser.next_token() 562 564 if token.contents == 'else': … … 565 567 else: 566 568 nodelist_false = NodeList() 567 569 return IfNode(boolvars, nodelist_true, nodelist_false) 570 do_if = register.tag("if", do_if) 568 571 569 def do_ifchanged(parser, token): 572 #@register.tag 573 def ifchanged(parser, token): 570 574 """ 571 575 Check if a value has changed from the last iteration of a loop. 572 576 … … 587 591 nodelist = parser.parse(('endifchanged',)) 588 592 parser.delete_first_token() 589 593 return IfChangedNode(nodelist) 594 ifchanged = register.tag(ifchanged) 590 595 591 def do_ssi(parser, token): 596 #@register.tag 597 def ssi(parser, token): 592 598 """ 593 599 Output the contents of a given file into the page. 594 600 … … 613 619 else: 614 620 raise TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0] 615 621 return SsiNode(bits[1], parsed) 622 ssi = register.tag(ssi) 616 623 617 def do_load(parser, token): 624 #@register.tag 625 def load(parser, token): 618 626 """ 619 627 Load a custom template tag set. 620 628 … … 623 631 {% load news.photos %} 624 632 """ 625 633 bits = token.contents.split() 626 if len(bits) != 2:627 raise TemplateSyntaxError, "'load' statement takes one argument"628 taglib = bits[1]629 # check at compile time that the module can be imported630 try:631 LoadNode.load_taglib(taglib)632 except ImportError, e:633 raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e)634 return LoadNode(taglib)634 for taglib in bits[1:]: 635 # add the library to the parser 636 try: 637 lib = get_library("django.templatetags.%s" % taglib.split('.')[-1]) 638 parser.add_library(lib) 639 except InvalidTemplateLibraryException, e: 640 raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e) 641 return LoadNode() 642 load = register.tag(load) 635 643 636 def do_now(parser, token): 644 #@register.tag 645 def now(parser, token): 637 646 """ 638 647 Display the date, formatted according to the given string. 639 648 … … 649 658 raise TemplateSyntaxError, "'now' statement takes one argument" 650 659 format_string = bits[1] 651 660 return NowNode(format_string) 661 now = register.tag(now) 652 662 653 def do_regroup(parser, token): 663 #@register.tag 664 def regroup(parser, token): 654 665 """ 655 666 Regroup a list of alike objects by a common attribute. 656 667 … … 699 710 firstbits = token.contents.split(None, 3) 700 711 if len(firstbits) != 4: 701 712 raise TemplateSyntaxError, "'regroup' tag takes five arguments" 702 target _var = firstbits[1]713 target = parser.compile_filter(firstbits[1]) 703 714 if firstbits[2] != 'by': 704 715 raise TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'" 705 716 lastbits_reversed = firstbits[3][::-1].split(None, 2) 706 717 if lastbits_reversed[1][::-1] != 'as': 707 718 raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'" 708 expression = lastbits_reversed[2][::-1] 719 720 expression = parser.compile_filters('var.%s' % lastbits_reversed[2][::-1]) 721 709 722 var_name = lastbits_reversed[0][::-1] 710 return RegroupNode(target_var, expression, var_name) 723 return RegroupNode(target, expression, var_name) 724 regroup = register.tag(regroup) 711 725 712 def do_templatetag(parser, token): 726 #@register.tag 727 def templatetag(parser, token): 713 728 """ 714 729 Output one of the bits used to compose template tags. 715 730 … … 735 750 raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \ 736 751 (tag, TemplateTagNode.mapping.keys()) 737 752 return TemplateTagNode(tag) 753 templatetag = register.tag(templatetag) 738 754 739 def do_widthratio(parser, token): 755 @register.tag 756 def widthratio(parser, token): 740 757 """ 741 758 For creating bar charts and such, this tag calculates the ratio of a given 742 759 value to a maximum value, and then applies that ratio to a constant. … … 752 769 bits = token.contents.split() 753 770 if len(bits) != 4: 754 771 raise TemplateSyntaxError("widthratio takes three arguments") 755 tag, this_value_ var, max_value_var, max_width = bits772 tag, this_value_expr, max_value_expr, max_width = bits 756 773 try: 757 774 max_width = int(max_width) 758 775 except ValueError: 759 776 raise TemplateSyntaxError("widthratio final argument must be an integer") 760 return WidthRatioNode(this_value_var, max_value_var, max_width) 761 762 register_tag('comment', do_comment) 763 register_tag('cycle', do_cycle) 764 register_tag('debug', do_debug) 765 register_tag('filter', do_filter) 766 register_tag('firstof', do_firstof) 767 register_tag('for', do_for) 768 register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False)) 769 register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True)) 770 register_tag('if', do_if) 771 register_tag('ifchanged', do_ifchanged) 772 register_tag('regroup', do_regroup) 773 register_tag('ssi', do_ssi) 774 register_tag('load', do_load) 775 register_tag('now', do_now) 776 register_tag('templatetag', do_templatetag) 777 register_tag('widthratio', do_widthratio) 777 return WidthRatioNode(parser.compile_filter(this_value_expr), 778 parser.compile_filter(max_value_expr), max_width) 779 widthratio = register.tag(widthratio) -
django/core/template/loader_tags.py
=== django/core/template/loader_tags.py ==================================================================
1 from django.core.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable 2 from django.core.template import Library, Context, Node 3 from django.core.template.loader import get_template, get_template_from_string, find_template_source 4 from django.conf.settings import TEMPLATE_DEBUG 5 register = Library() 6 7 class ExtendsError(Exception): 8 pass 9 10 class BlockNode(Node): 11 def __init__(self, name, nodelist, parent=None): 12 self.name, self.nodelist, self.parent = name, nodelist, parent 13 14 def __repr__(self): 15 return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist) 16 17 def render(self, context): 18 context.push() 19 # Save context in case of block.super(). 20 self.context = context 21 context['block'] = self 22 result = self.nodelist.render(context) 23 context.pop() 24 return result 25 26 def super(self): 27 if self.parent: 28 return self.parent.render(self.context) 29 return '' 30 31 def add_parent(self, nodelist): 32 if self.parent: 33 self.parent.add_parent(nodelist) 34 else: 35 self.parent = BlockNode(self.name, nodelist) 36 37 class ExtendsNode(Node): 38 def __init__(self, nodelist, parent_name, parent_name_expr, template_dirs=None): 39 self.nodelist = nodelist 40 self.parent_name, self.parent_name_expr = parent_name, parent_name_expr 41 self.template_dirs = template_dirs 42 43 def get_parent(self, context): 44 if self.parent_name_expr: 45 self.parent_name = self.parent_name_expr.resolve(context) 46 parent = self.parent_name 47 if not parent: 48 error_msg = "Invalid template name in 'extends' tag: %r." % parent 49 if self.parent_name_expr: 50 error_msg += " Got this from the %r variable." % self.parent_name_expr #TODO nice repr. 51 raise TemplateSyntaxError, error_msg 52 try: 53 return get_template_from_string(*find_template_source(parent, self.template_dirs)) 54 except TemplateDoesNotExist: 55 raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent 56 57 def render(self, context): 58 compiled_parent = self.get_parent(context) 59 parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode) 60 parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) 61 for block_node in self.nodelist.get_nodes_by_type(BlockNode): 62 # Check for a BlockNode with this node's name, and replace it if found. 63 try: 64 parent_block = parent_blocks[block_node.name] 65 except KeyError: 66 # This BlockNode wasn't found in the parent template, but the 67 # parent block might be defined in the parent's *parent*, so we 68 # add this BlockNode to the parent's ExtendsNode nodelist, so 69 # it'll be checked when the parent node's render() is called. 70 if parent_is_child: 71 compiled_parent.nodelist[0].nodelist.append(block_node) 72 else: 73 # Keep any existing parents and add a new one. Used by BlockNode. 74 parent_block.parent = block_node.parent 75 parent_block.add_parent(parent_block.nodelist) 76 parent_block.nodelist = block_node.nodelist 77 return compiled_parent.render(context) 78 79 class ConstantIncludeNode(Node): 80 def __init__(self, template_path): 81 try: 82 t = get_template(template_path) 83 self.template = t 84 except Exception, e: 85 if TEMPLATE_DEBUG: 86 raise 87 self.template = None 88 89 def render(self, context): 90 if self.template: 91 return self.template.render(context) 92 else: 93 return '' 94 95 class IncludeNode(Node): 96 def __init__(self, template_name): 97 self.template_name = template_name 98 99 def render(self, context): 100 try: 101 template_name = resolve_variable(self.template_name, context) 102 t = get_template(template_name) 103 return t.render(context) 104 except TemplateSyntaxError, e: 105 if TEMPLATE_DEBUG: 106 raise 107 return '' 108 except: 109 return '' # Fail silently for invalid included templates. 110 111 def do_block(parser, token): 112 """ 113 Define a block that can be overridden by child templates. 114 """ 115 bits = token.contents.split() 116 if len(bits) != 2: 117 raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0] 118 block_name = bits[1] 119 # Keep track of the names of BlockNodes found in this template, so we can 120 # check for duplication. 121 try: 122 if block_name in parser.__loaded_blocks: 123 raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name) 124 parser.__loaded_blocks.append(block_name) 125 except AttributeError: # parser._loaded_blocks isn't a list yet 126 parser.__loaded_blocks = [block_name] 127 nodelist = parser.parse(('endblock',)) 128 parser.delete_first_token() 129 return BlockNode(block_name, nodelist) 130 131 def do_extends(parser, token): 132 """ 133 Signal that this template extends a parent template. 134 135 This tag may be used in two ways: ``{% extends "base" %}`` (with quotes) 136 uses the literal value "base" as the name of the parent template to extend, 137 or ``{% extends variable %}`` uses the value of ``variable`` as the name 138 of the parent template to extend. 139 """ 140 bits = token.contents.split() 141 if len(bits) != 2: 142 raise TemplateSyntaxError, "'%s' takes one argument" % bits[0] 143 parent_name, parent_name_expr = None, None 144 if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]: 145 parent_name = bits[1][1:-1] 146 else: 147 parent_name_expr = parser.compile_filter(bits[1]) 148 nodelist = parser.parse() 149 if nodelist.get_nodes_by_type(ExtendsNode): 150 raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0] 151 return ExtendsNode(nodelist, parent_name, parent_name_expr) 152 153 def do_include(parser, token): 154 """ 155 Loads a template and renders it with the current context. 156 157 Example:: 158 159 {% include "foo/some_include" %} 160 """ 161 162 bits = token.contents.split() 163 if len(bits) != 2: 164 raise TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0] 165 path = bits[1] 166 if path[0] in ('"', "'") and path[-1] == path[0]: 167 return ConstantIncludeNode(path[1:-1]) 168 return IncludeNode(bits[1]) 169 170 register.tag('block', do_block) 171 register.tag('extends', do_extends) 172 register.tag('include', do_include) 173 No newline at end of file -
django/core/template/loader.py
=== django/core/template/loader.py ==================================================================
21 21 # installed, because pkg_resources is necessary to read eggs. 22 22 23 23 from django.core.exceptions import ImproperlyConfigured 24 from django.core.template import Origin, StringOrigin, Template, Context, Node, TemplateDoesNotExist, TemplateSyntaxError, resolve_variable_with_filters, resolve_variable, register_tag24 from django.core.template import Origin, StringOrigin, Template, TemplateDoesNotExist, add_to_builtins 25 25 from django.conf.settings import TEMPLATE_LOADERS, TEMPLATE_DEBUG 26 26 27 27 template_source_loaders = [] … … 68 68 def load_template_source(name, dirs=None): 69 69 find_template_source(name, dirs)[0] 70 70 71 class ExtendsError(Exception):72 pass73 74 71 def get_template(template_name): 75 72 """ 76 73 Returns a compiled Template object for the given template name, … … 113 110 # If we get here, none of the templates could be loaded 114 111 raise TemplateDoesNotExist, ', '.join(template_name_list) 115 112 116 class BlockNode(Node): 117 def __init__(self, name, nodelist, parent=None): 118 self.name, self.nodelist, self.parent = name, nodelist, parent 119 120 def __repr__(self): 121 return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist) 122 123 def render(self, context): 124 context.push() 125 # Save context in case of block.super(). 126 self.context = context 127 context['block'] = self 128 result = self.nodelist.render(context) 129 context.pop() 130 return result 131 132 def super(self): 133 if self.parent: 134 return self.parent.render(self.context) 135 return '' 136 137 def add_parent(self, nodelist): 138 if self.parent: 139 self.parent.add_parent(nodelist) 140 else: 141 self.parent = BlockNode(self.name, nodelist) 142 143 class ExtendsNode(Node): 144 def __init__(self, nodelist, parent_name, parent_name_var, template_dirs=None): 145 self.nodelist = nodelist 146 self.parent_name, self.parent_name_var = parent_name, parent_name_var 147 self.template_dirs = template_dirs 148 149 def get_parent(self, context): 150 if self.parent_name_var: 151 self.parent_name = resolve_variable_with_filters(self.parent_name_var, context) 152 parent = self.parent_name 153 if not parent: 154 error_msg = "Invalid template name in 'extends' tag: %r." % parent 155 if self.parent_name_var: 156 error_msg += " Got this from the %r variable." % self.parent_name_var 157 raise TemplateSyntaxError, error_msg 158 try: 159 return get_template_from_string(*find_template_source(parent, self.template_dirs)) 160 except TemplateDoesNotExist: 161 raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent 162 163 def render(self, context): 164 compiled_parent = self.get_parent(context) 165 parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode) 166 parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)]) 167 for block_node in self.nodelist.get_nodes_by_type(BlockNode): 168 # Check for a BlockNode with this node's name, and replace it if found. 169 try: 170 parent_block = parent_blocks[block_node.name] 171 except KeyError: 172 # This BlockNode wasn't found in the parent template, but the 173 # parent block might be defined in the parent's *parent*, so we 174 # add this BlockNode to the parent's ExtendsNode nodelist, so 175 # it'll be checked when the parent node's render() is called. 176 if parent_is_child: 177 compiled_parent.nodelist[0].nodelist.append(block_node) 178 else: 179 # Keep any existing parents and add a new one. Used by BlockNode. 180 parent_block.parent = block_node.parent 181 parent_block.add_parent(parent_block.nodelist) 182 parent_block.nodelist = block_node.nodelist 183 return compiled_parent.render(context) 184 185 class ConstantIncludeNode(Node): 186 def __init__(self, template_path): 187 try: 188 t = get_template(template_path) 189 self.template = t 190 except Exception, e: 191 if TEMPLATE_DEBUG: 192 raise 193 self.template = None 194 195 def render(self, context): 196 if self.template: 197 return self.template.render(context) 198 else: 199 return '' 200 201 class IncludeNode(Node): 202 def __init__(self, template_name): 203 self.template_name = template_name 204 205 def render(self, context): 206 try: 207 template_name = resolve_variable(self.template_name, context) 208 t = get_template(template_name) 209 return t.render(context) 210 except TemplateSyntaxError, e: 211 if TEMPLATE_DEBUG: 212 raise 213 return '' 214 except: 215 return '' # Fail silently for invalid included templates. 216 217 def do_block(parser, token): 218 """ 219 Define a block that can be overridden by child templates. 220 """ 221 bits = token.contents.split() 222 if len(bits) != 2: 223 raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0] 224 block_name = bits[1] 225 # Keep track of the names of BlockNodes found in this template, so we can 226 # check for duplication. 227 try: 228 if block_name in parser.__loaded_blocks: 229 raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name) 230 parser.__loaded_blocks.append(block_name) 231 except AttributeError: # parser._loaded_blocks isn't a list yet 232 parser.__loaded_blocks = [block_name] 233 nodelist = parser.parse(('endblock',)) 234 parser.delete_first_token() 235 return BlockNode(block_name, nodelist) 236 237 def do_extends(parser, token): 238 """ 239 Signal that this template extends a parent template. 240 241 This tag may be used in two ways: ``{% extends "base" %}`` (with quotes) 242 uses the literal value "base" as the name of the parent template to extend, 243 or ``{% extends variable %}`` uses the value of ``variable`` as the name 244 of the parent template to extend. 245 """ 246 bits = token.contents.split() 247 if len(bits) != 2: 248 raise TemplateSyntaxError, "'%s' takes one argument" % bits[0] 249 parent_name, parent_name_var = None, None 250 if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]: 251 parent_name = bits[1][1:-1] 252 else: 253 parent_name_var = bits[1] 254 nodelist = parser.parse() 255 if nodelist.get_nodes_by_type(ExtendsNode): 256 raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0] 257 return ExtendsNode(nodelist, parent_name, parent_name_var) 258 259 def do_include(parser, token): 260 """ 261 Loads a template and renders it with the current context. 262 263 Example:: 264 265 {% include "foo/some_include" %} 266 """ 267 268 bits = token.contents.split() 269 if len(bits) != 2: 270 raise TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0] 271 path = bits[1] 272 if path[0] in ('"', "'") and path[-1] == path[0]: 273 return ConstantIncludeNode(path[1:-1]) 274 return IncludeNode(bits[1]) 275 276 register_tag('block', do_block) 277 register_tag('extends', do_extends) 278 register_tag('include', do_include) 113 114 add_to_builtins('django.core.template.loader_tags') 115 No newline at end of file -
django/core/template/decorators.py
=== django/core/template/decorators.py ==================================================================
1 from django.core.template import Context, Node, TemplateSyntaxError, register_tag, resolve_variable2 from django.core.template_loader import get_template3 from django.utils.functional import curry4 from inspect import getargspec5 6 def generic_tag_compiler(params, defaults, name, node_class, parser, token):7 "Returns a template.Node subclass."8 bits = token.contents.split()[1:]9 bmax = len(params)10 def_len = defaults and len(defaults) or 011 bmin = bmax - def_len12 if(len(bits) < bmin or len(bits) > bmax):13 if bmin == bmax:14 message = "%s takes %s arguments" % (name, bmin)15 else:16 message = "%s takes between %s and %s arguments" % (name, bmin, bmax)17 raise TemplateSyntaxError, message18 return node_class(bits)19 20 def simple_tag(func):21 (params, xx, xxx, defaults) = getargspec(func)22 23 class SimpleNode(Node):24 def __init__(self, vars_to_resolve):25 self.vars_to_resolve = vars_to_resolve26 27 def render(self, context):28 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]29 return func(*resolved_vars)30 31 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode)32 compile_func.__doc__ = func.__doc__33 register_tag(func.__name__, compile_func)34 return func35 36 def inclusion_tag(file_name, context_class=Context, takes_context=False):37 def dec(func):38 (params, xx, xxx, defaults) = getargspec(func)39 if takes_context:40 if params[0] == 'context':41 params = params[1:]42 else:43 raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'"44 45 class InclusionNode(Node):46 def __init__(self, vars_to_resolve):47 self.vars_to_resolve = vars_to_resolve48 49 def render(self, context):50 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]51 if takes_context:52 args = [context] + resolved_vars53 else:54 args = resolved_vars55 56 dict = func(*args)57 58 if not getattr(self, 'nodelist', False):59 t = get_template(file_name)60 self.nodelist = t.nodelist61 return self.nodelist.render(context_class(dict))62 63 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode)64 compile_func.__doc__ = func.__doc__65 register_tag(func.__name__, compile_func)66 return func67 return dec -
django/templatetags/i18n.py
Property changes on: ___________________________________________________________________ Name: svk:merge -bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:1440 +bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:1054 === django/templatetags/i18n.py ==================================================================
1 from django.core.template import Node, NodeList, Template, Context, resolve_variable , resolve_variable_with_filters, registered_filters2 from django.core.template import TemplateSyntaxError, register_tag, TokenParser1 from django.core.template import Node, NodeList, Template, Context, resolve_variable 2 from django.core.template import TemplateSyntaxError, TokenParser, Library 3 3 from django.core.template import TOKEN_BLOCK, TOKEN_TEXT, TOKEN_VAR 4 4 from django.utils import translation 5 5 import re, sys 6 6 7 register = Library() 8 7 9 class GetAvailableLanguagesNode(Node): 8 10 def __init__(self, variable): 9 11 self.variable = variable … … 53 55 def render(self, context): 54 56 context.push() 55 57 for var,val in self.extra_context.items(): 56 context[var] = resolve_variable_with_filters(val,context)58 context[var] = val.resolve(context) 57 59 singular = self.render_token_list(self.singular) 58 60 if self.plural and self.countervar and self.counter: 59 count = resolve_variable_with_filters(self.counter,context)61 count = self.counter.resolve(context) 60 62 context[self.countervar] = count 61 63 plural = self.render_token_list(self.plural) 62 64 result = translation.ngettext(singular, plural, count) % context … … 179 181 value = self.value() 180 182 if self.tag() != 'as': 181 183 raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'" 182 extra_context[self.tag()] = value184 extra_context[self.tag()] = parser.compile_filter(value) 183 185 elif tag == 'count': 184 counter = self.value()186 counter = parser.compile_filter(self.value()) 185 187 if self.tag() != 'as': 186 188 raise TemplateSyntaxError, "counter specification in 'blocktrans' must be 'count value as variable'" 187 189 countervar = self.tag() … … 191 193 192 194 (countervar, counter, extra_context) = BlockTranslateParser(token.contents).top() 193 195 196 194 197 singular = [] 195 198 plural = [] 196 199 while parser.tokens: … … 213 216 214 217 return BlockTranslateNode(extra_context, singular, plural, countervar, counter) 215 218 216 register _tag('get_available_languages', do_get_available_languages)217 register _tag('get_current_language', do_get_current_language)218 register _tag('trans', do_translate)219 register _tag('blocktrans', do_block_translate)219 register.tag('get_available_languages', do_get_available_languages) 220 register.tag('get_current_language', do_get_current_language) 221 register.tag('trans', do_translate) 222 register.tag('blocktrans', do_block_translate) -
tests/testapp/templatetags/testtags.py
=== tests/testapp/templatetags/testtags.py ==================================================================
2 2 3 3 from django.core import template 4 4 5 register = template.Library() 6 5 7 class EchoNode(template.Node): 6 8 def __init__(self, contents): 7 9 self.contents = contents … … 11 13 12 14 def do_echo(parser, token): 13 15 return EchoNode(token.contents.split()[1:]) 14 15 template.register_tag("echo", do_echo)16 No newline at end of file 16 17 register.tag("echo", do_echo) 18 No newline at end of file -
tests/othertests/defaultfilters.py
=== tests/othertests/defaultfilters.py ==================================================================
1 1 """ 2 >>> floatformat(7.7 , None)2 >>> floatformat(7.7) 3 3 '7.7' 4 >>> floatformat(7.0 , None)4 >>> floatformat(7.0) 5 5 '7' 6 >>> floatformat(0.7 , None)6 >>> floatformat(0.7) 7 7 '0.7' 8 >>> floatformat(0.07 , None)8 >>> floatformat(0.07) 9 9 '0.1' 10 >>> floatformat(0.007 , None)10 >>> floatformat(0.007) 11 11 '0.0' 12 >>> floatformat(0.0 , None)12 >>> floatformat(0.0) 13 13 '0' 14 14 """ 15 15 -
tests/othertests/templates.py
=== tests/othertests/templates.py ==================================================================
102 102 #Escaped string as argument 103 103 'basic-syntax30': (r"""{{ var|default_if_none:" endquote\" hah" }}""", {"var": None}, ' endquote" hah'), 104 104 105 # Variable as argument 106 'basic-syntax31': (r"""{{ var|default_if_none:var2 }}""", {"var":None, "var2": "happy" }, 'happy'), 107 108 #Default argument testing 109 'basic-syntax32' : (r"""{{ var|yesno:"yup,nup,mup" }} {{var|yesno}}""", {"var": True}, 'yup yes'), 110 105 111 ### IF TAG ################################################################ 106 112 'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"), 107 113 'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"), -
tests/othertests/markup.py
=== tests/othertests/markup.py ==================================================================
1 1 # Quick tests for the markup templatetags (django.contrib.markup) 2 2 3 from django.core.template import Template, Context 4 import django.contrib.markup.templatetags.markup # this registers the filters 3 from django.core.template import Template, Context, add_to_builtins 5 4 5 add_to_builtins('django.contrib.markup.templatetags.markup') 6 6 7 # find out if markup modules are installed and tailor the test appropriately 7 8 try: 8 9 import textile -
docs/templates_python.txt
=== docs/templates_python.txt ==================================================================
444 444 Once you've created that Python module, you'll just have to write a bit of 445 445 Python code, depending on whether you're writing filters or tags. 446 446 447 To be a valid tag library, a module must have a member that is a template.Library 448 instance, in which all the tags and filters are registered. So at the top of your 449 module, put the following: 450 451 from django.core import template 452 register = template.Library() 453 454 It is convention to call this instance ``register``. 455 447 456 .. admonition:: Behind the scenes 448 457 449 458 For a ton of examples, read the source code for Django's default filters … … 453 462 Writing custom template filters 454 463 ------------------------------- 455 464 456 Custom filters are just Python functions that take two arguments:465 Custom filters are just Python functions that take one or two arguments: 457 466 458 467 * The value of the variable (input) -- not necessarily a string 459 * The value of the argument -- always a string 468 * The value of the argument -- this can have a default value, or be left 469 out altogether 460 470 461 471 Filter functions should always return something. They shouldn't raise 462 472 exceptions. They should fail silently. In case of error, they should return … … 468 478 "Removes all values of arg from the given string" 469 479 return value.replace(arg, '') 470 480 471 Most filters don't take arguments. For filters that don't take arguments, the 472 convention is to use a single underscore as the second argument to the filter 473 definition. Example:: 481 Most filters don't take arguments. Example:: 474 482 475 def lower(value , _):483 def lower(value): 476 484 "Converts a string into all lowercase" 477 485 return value.lower() 478 486 479 When you've written your filter definition, you need to register it , to make it480 available to Django's template language::487 When you've written your filter definition, you need to register it with 488 your Library instance, to make it available to Django's template language:: 481 489 482 from django.core import template 483 template.register_filter('cut', cut, True) 484 template.register_filter('lower', lower, False) 490 register.filter('cut', cut) 491 register.filter('lower', lower) 485 492 486 ``register_filter`` takes threearguments:493 this takes two arguments: 487 494 488 495 1. The name of the filter -- a string. 489 496 2. The compilation function -- a Python function (not the name of the 490 497 function as a string). 491 3. A boolean, designating whether the filter requires an argument. This492 tells Django's template parser whether to throw ``TemplateSyntaxError``493 when filter arguments are given (or missing).494 498 495 The convention is to put all ``register_filter`` calls at the bottom of your 496 template-library module. 499 It can also be used as a decorator if you are using python 2.4 or above: 500 501 @register.filter(name="cheese") 502 def cheese_filter(value, arg="Wensleydale"): 503 return "%s likes %s" % (value, arg) 504 505 @register.filter 506 def lower(value): 507 return value.lower() 497 508 509 If you leave out the name of the filter, as in the second example above, the functions 510 name will be used as the filter name. 511 498 512 Writing custom template tags 499 513 ---------------------------- 500 514 … … 525 539 function with the tag contents and the parser object itself. This function is 526 540 responsible for returning a ``Node`` instance based on the contents of the tag. 527 541 528 By convention, the name of each compilation function should start with ``do_``.529 530 542 For example, let's write a template tag, ``{% current_time %}``, that displays 531 543 the current date/time, formatted according to a parameter given in the tag, in 532 544 `strftime syntax`_. It's a good idea to decide the tag syntax before anything … … 612 624 Registering the tag 613 625 ~~~~~~~~~~~~~~~~~~~ 614 626 615 Finally, use a ``register_tag`` call, as in ``register_filter`` above. Example::627 Finally, register the tag with your modules Library instance. Example:: 616 628 617 from django.core import template 618 template.register_tag('current_time', do_current_time) 629 register.tag('current_time', do_current_time) 619 630 620 ``register_tag``takes two arguments:631 this takes two arguments: 621 632 622 1. The name of the template tag -- a string. 633 1. The name of the template tag -- a string. If this is left out, the 634 name of the compilation function will be used. 623 635 2. The compilation function -- a Python function (not the name of the 624 636 function as a string). 625 637 638 As with filter registration, it is also possible to use this as a decorator in 639 Python 2.4 and above: 640 641 @register.tag 642 def shout(parser, token): 643 ... 644 645 @register.tag(name="milk") 646 def do_milk(parser, token): 647 ... 648 626 649 Setting a variable in the context 627 650 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 628 651