Ticket #1400: templates_r2738.diff
File templates_r2738.diff, 38.1 KB (added by , 19 years ago) |
---|
-
django/contrib/admin/templatetags/admin_list.py
=== django/contrib/admin/templatetags/admin_list.py ==================================================================
65 65 'ALL_VAR': ALL_VAR, 66 66 '1': 1, 67 67 } 68 pagination = register.inclusion_tag( 'admin/pagination.html')(pagination)68 pagination = register.inclusion_tag(pagination, 'admin/pagination.html') 69 69 70 70 def result_headers(cl): 71 71 lookup_opts = cl.lookup_opts … … 185 185 return {'cl': cl, 186 186 'result_headers': list(result_headers(cl)), 187 187 'results': list(results(cl))} 188 result_list = register.inclusion_tag( "admin/change_list_results.html")(result_list)188 result_list = register.inclusion_tag(result_list, 'admin/change_list_results.html') 189 189 190 190 def date_hierarchy(cl): 191 191 if cl.lookup_opts.admin.date_hierarchy: … … 245 245 'title': year.year 246 246 } for year in years] 247 247 } 248 date_hierarchy = register.inclusion_tag( 'admin/date_hierarchy.html')(date_hierarchy)248 date_hierarchy = register.inclusion_tag(date_hierarchy, 'admin/date_hierarchy.html') 249 249 250 250 def search_form(cl): 251 251 return { … … 253 253 'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field, 254 254 'search_var': SEARCH_VAR 255 255 } 256 search_form = register.inclusion_tag( 'admin/search_form.html')(search_form)256 search_form = register.inclusion_tag(search_form, 'admin/search_form.html') 257 257 258 258 def filter(cl, spec): 259 259 return {'title': spec.title(), 'choices' : list(spec.choices(cl))} 260 filter = register.inclusion_tag( 'admin/filter.html')(filter)260 filter = register.inclusion_tag(filter, 'admin/filter.html') 261 261 262 262 def filters(cl): 263 263 return {'cl': cl} 264 filters = register.inclusion_tag( 'admin/filters.html')(filters)264 filters = register.inclusion_tag(filters, 'admin/filters.html') -
django/contrib/admin/templatetags/admin_modify.py
=== django/contrib/admin/templatetags/admin_modify.py ==================================================================
22 22 include_admin_script = register.simple_tag(include_admin_script) 23 23 24 24 def submit_row(context): 25 opts = context ['opts']26 change = context ['change']27 is_popup = context ['is_popup']25 opts = context.get('opts') 26 change = context.get('change') 27 is_popup = context.get('is_popup') 28 28 return { 29 29 'onclick_attrib': (opts.get_ordered_objects() and change 30 30 and 'onclick="submitOrderForm();"' or ''), … … 35 35 'show_save_and_continue': not is_popup and context['has_change_permission'], 36 36 'show_save': True 37 37 } 38 submit_row = register.inclusion_tag( 'admin/submit_line.html', takes_context=True)(submit_row)38 submit_row = register.inclusion_tag(submit_row, 'admin/submit_line.html', takes_context=True) 39 39 40 40 def field_label(bound_field): 41 41 class_names = [] … … 229 229 'bound_fields': bound_fields, 230 230 'class_names': " ".join(class_names), 231 231 } 232 admin_field_line = register.inclusion_tag( 'admin/field_line.html', takes_context=True)(admin_field_line)232 admin_field_line = register.inclusion_tag(admin_field_line, 'admin/field_line.html', takes_context=True) -
django/contrib/admin/templatetags/adminapplist.py
=== django/contrib/admin/templatetags/adminapplist.py ==================================================================
61 61 raise template.TemplateSyntaxError, "First argument to '%s' tag must be 'as'" % tokens[0] 62 62 return AdminApplistNode(tokens[2]) 63 63 64 register.tag( 'get_admin_app_list', get_admin_app_list)64 register.tag(get_admin_app_list, name='get_admin_app_list') -
django/contrib/admin/templatetags/log.py
=== django/contrib/admin/templatetags/log.py ==================================================================
50 50 raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user'" % self.tag_name 51 51 return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(len(tokens) > 5 and tokens[5] or None)) 52 52 53 register.tag( 'get_admin_log', DoGetAdminLog('get_admin_log'))53 register.tag(DoGetAdminLog('get_admin_log'), name='get_admin_log') -
django/contrib/admin/views/template.py
=== django/contrib/admin/views/template.py ==================================================================
56 56 node.template_dirs = settings_module.TEMPLATE_DIRS 57 57 return node 58 58 register = template.Library() 59 register.tag( 'extends', new_do_extends)59 register.tag(new_do_extends, name='extends') 60 60 template.builtins.append(register) 61 61 62 62 # Now validate the template using the new template dirs -
django/contrib/comments/templatetags/comments.py
=== django/contrib/comments/templatetags/comments.py ==================================================================
313 313 return CommentListNode(package, module, var_name, obj_id, tokens[5], self.free, ordering) 314 314 315 315 # registration comments 316 register.tag( 'get_comment_list', DoGetCommentList(False))317 register.tag( 'comment_form', DoCommentForm(False))318 register.tag( 'get_comment_count', DoCommentCount(False))316 register.tag(DoGetCommentList(False), name='get_comment_list') 317 register.tag(DoCommentForm(False), name='comment_form') 318 register.tag(DoCommentCount(False), name='get_comment_count') 319 319 # free comments 320 register.tag( 'get_free_comment_list', DoGetCommentList(True))321 register.tag( 'free_comment_form', DoCommentForm(True))322 register.tag( 'get_free_comment_count', DoCommentCount(True))320 register.tag(DoGetCommentList(True), name='get_free_comment_list') 321 register.tag(DoCommentForm(True), name='free_comment_form') 322 register.tag(DoCommentCount(True), name='get_free_comment_count') -
django/template/__init__.py
=== django/template/__init__.py ==================================================================
54 54 >>> t.render(c) 55 55 '\n<html>\n\n</html>\n' 56 56 """ 57 import keyword 57 58 import re 58 59 from inspect import getargspec 59 60 from django.utils.functional import curry … … 76 77 VARIABLE_TAG_END = '}}' 77 78 78 79 ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.' 80 BOOLEANS = ['False', 'True'] 79 81 80 82 # what to report as the origin for templates that come from non-loader sources 81 83 # (e.g. strings) … … 223 225 elif token.token_type == TOKEN_VAR: 224 226 if not token.contents: 225 227 self.empty_variable(token) 226 filter_expression = self.compile_filter(token.contents )228 filter_expression = self.compile_filter(token.contents, default=settings.TEMPLATE_STRING_IF_INVALID) 227 229 var_node = self.create_variable_node(filter_expression) 228 230 self.extend_nodelist(nodelist, var_node,token) 229 231 elif token.token_type == TOKEN_BLOCK: … … 305 307 self.tags.update(lib.tags) 306 308 self.filters.update(lib.filters) 307 309 308 def compile_filter(self, token):310 def compile_filter(self, token, default=None): 309 311 "Convenient wrapper for FilterExpression" 310 return FilterExpression(token, self )312 return FilterExpression(token, self, default) 311 313 312 314 def find_filter(self, filter_name): 313 315 if self.filters.has_key(filter_name): … … 492 494 This class should never be instantiated outside of the 493 495 get_filters_from_token helper function. 494 496 """ 495 def __init__(self, token, parser ):497 def __init__(self, token, parser, default=None): 496 498 self.token = token 497 matches = filter_re.finditer(token)499 self.default = default 498 500 var = None 499 501 filters = [] 500 502 upto = 0 501 for match in matches:503 for match in filter_re.finditer(token): 502 504 start = match.start() 503 505 if upto != start: 504 506 raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s" % \ … … 530 532 upto = match.end() 531 533 if upto != len(token): 532 534 raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] 533 self.var 535 self.var, self.filters = var, filters 534 536 535 537 def resolve(self, context): 536 538 try: 537 539 obj = resolve_variable(self.var, context) 538 540 except VariableDoesNotExist: 539 obj = settings.TEMPLATE_STRING_IF_INVALID541 return self.default 540 542 for func, args in self.filters: 541 543 arg_vals = [] 542 544 for lookup, arg in args: … … 584 586 """ 585 587 Returns the resolved variable, which may contain attribute syntax, within 586 588 the given context. The variable may be a hard-coded string (if it begins 587 and ends with single or double quote marks). 589 and ends with single or double quote marks), a boolean literal, or an 590 integer or float literal. 588 591 589 592 >>> c = {'article': {'section':'News'}} 590 593 >>> resolve_variable('article.section', c) … … 600 603 601 604 (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 602 605 """ 603 if path[0] in '0123456789':606 if path[0].isdigit(): 604 607 number_type = '.' in path and float or int 605 try: 606 current = number_type(path) 607 except ValueError: 608 current = settings.TEMPLATE_STRING_IF_INVALID 609 elif path[0] in ('"', "'") and path[0] == path[-1]: 610 current = path[1:-1] 611 else: 612 current = context 613 bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) 614 while bits: 615 try: # dictionary lookup 616 current = current[bits[0]] 617 except (TypeError, AttributeError, KeyError): 618 try: # attribute lookup 619 current = getattr(current, bits[0]) 620 if callable(current): 621 if getattr(current, 'alters_data', False): 622 current = settings.TEMPLATE_STRING_IF_INVALID 623 else: 624 try: # method call (assuming no args required) 625 current = current() 626 except TypeError: # arguments *were* required 627 # GOTCHA: This will also catch any TypeError 628 # raised in the function itself. 629 current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call 630 except Exception, e: 631 if getattr(e, 'silent_variable_failure', False): 632 current = settings.TEMPLATE_STRING_IF_INVALID 633 else: 634 raise 635 except (TypeError, AttributeError): 636 try: # list-index lookup 637 current = current[int(bits[0])] 638 except (IndexError, ValueError, KeyError): 639 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bits[0], current) # missing attribute 640 except Exception, e: 641 if getattr(e, 'silent_variable_failure', False): 642 current = settings.TEMPLATE_STRING_IF_INVALID 643 else: 644 raise 645 del bits[0] 646 return current 608 return number_type(path) 609 if path in BOOLEANS: 610 return bool(BOOLEANS.index(path)) 611 if path[0] in ('"', "'"): 612 if path[0] == path[-1]: 613 return path[1:-1] 614 raise VariableDoesNotExist, "Missing quotes in string literal %s" % (path,) 615 for bit in path.split(VARIABLE_ATTRIBUTE_SEPARATOR): 616 try: # dictionary lookup 617 context = context[bit] 618 except (TypeError, AttributeError, KeyError): 619 try: # attribute lookup 620 context = getattr(context, bit) 621 except (TypeError, AttributeError): 622 try: # list-index lookup 623 context = context[int(bit)] 624 except (IndexError, ValueError, KeyError): 625 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute 626 else: 627 if callable(context): 628 if getattr(context, 'alters_data', False): 629 raise VariableDoesNotExist("Failed lookup for key [%s] in %r" % (bit, context)) 630 try: # method call (assuming no args required) 631 context = context() 632 except Exception, e: 633 if getattr(e, 'silent_variable_failure', False): 634 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute 635 raise 636 return context 647 637 638 tag_tokens_re = re.compile(r""" 639 (?:\s*) # ignore preceeding whitespace 640 ( # token group 641 (?:[A-Za-z_][0-9A-Za-z_]*=)?" # optional name and open double-quote 642 [^"\\]* # normal characters 643 (?:\\. # chew up backslash and following char 644 (?:|[^"\\])* # normal characters 645 )* # repeat as needed to chew up the backslashes 646 " # close double-quote 647 | 648 (?:[A-Za-z_][0-9A-Za-z_]*=)?' # optional name and open single-quote 649 [^'\\]* # normal characters 650 (?:\\. # chew up backslash and following char 651 (?:|[^'\\])* # normal characters 652 )* # repeat as needed to chew up the backslashes 653 ' # close single-quote 654 | 655 (?:[A-Za-z_][0-9A-Za-z_]*=)? # optional name 656 [^"'\s][^\s]* # unquoted token 657 ) 658 (?:\s+|$) # chew up following ws until next token 659 """, re.VERBOSE) 660 661 def tokenize_tag_contents(contents): 662 663 """ Parse tag contents into (tag_name, args_to_resolve, kwds_to_resolve). 664 If an argument name is a Python keyword append an underscore. 665 666 >>> tokenize_tag_contents("An 'easy' one.") 667 ('An', ["'easy'", 'one.'], {}) 668 >>> tokenize_tag_contents(r'''Please don't try 'thi\\'s at' named="hom\\"e."''') 669 ('Please', ["don't", 'try', "'thi\'s at'"], {'named': '"hom\\\\"e."'}) 670 """ 671 672 bits = [] 673 i, n = 0, len(contents) 674 while i < n: 675 m = tag_tokens_re.match(contents, i) 676 if not m: 677 raise ValueError("Can't parse string %s at index %s" %(repr(contents), i)) 678 bit = m.group(1) 679 if bit.startswith('"'): 680 bit = bit.replace('\\"', '"') 681 elif bit.startswith("'"): 682 bit = bit.replace("\\'", "'") 683 bits.append(bit) 684 i = m.end() 685 tag_name = bits[0] 686 args_to_resolve = [] 687 kwds_to_resolve = {} 688 for bit in bits[1:]: 689 if bit[0] in ("'", '"'): 690 if kwds_to_resolve: 691 raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments") 692 args_to_resolve.append(bit) 693 else: 694 try: 695 name, value = bit.split('=', 1) 696 if keyword.iskeyword(name): 697 name += '_' 698 kwds_to_resolve[name] = value 699 except ValueError: 700 if kwds_to_resolve: 701 raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments") 702 args_to_resolve.append(bit) 703 return tag_name, args_to_resolve, kwds_to_resolve 704 705 def resolve_tag_arguments(context, args_to_resolve, kwds_to_resolve): 706 resolved_args = [resolve_variable(var, context) for var in args_to_resolve] 707 resolved_kwds = dict([(name, resolve_variable(var, context)) for name, var in kwds_to_resolve.items()]) 708 return resolved_args, resolved_kwds 709 648 710 class Node: 649 711 def render(self, context): 650 712 "Return the node rendered as a string" … … 738 800 raise 739 801 return self.encode_output(output) 740 802 741 def generic_tag_compiler(params, defaults, name, node_class, parser, token): 742 "Returns a template.Node subclass." 743 bits = token.contents.split()[1:] 744 bmax = len(params) 745 def_len = defaults and len(defaults) or 0 746 bmin = bmax - def_len 747 if(len(bits) < bmin or len(bits) > bmax): 748 if bmin == bmax: 749 message = "%s takes %s arguments" % (name, bmin) 750 else: 751 message = "%s takes between %s and %s arguments" % (name, bmin, bmax) 752 raise TemplateSyntaxError, message 753 return node_class(bits) 803 class SimpleNode(Node): 804 def __init__(self, func, takes_context, block_nodelist, args_to_resolve, kwds_to_resolve): 805 self.func = func 806 self.takes_context = takes_context 807 self.block_nodelist = block_nodelist 808 self.args_to_resolve = args_to_resolve 809 self.kwds_to_resolve = kwds_to_resolve 754 810 755 class Library(object): 756 def __init__(self): 757 self.filters = {} 758 self.tags = {} 811 def render(self, context): 812 resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve) 813 if self.block_nodelist: 814 resolved_args.insert(0, self.block_nodelist) 815 if self.takes_context: 816 resolved_args.insert(0, context) 817 return self.func(*resolved_args, **resolved_kwds) or '' 759 818 760 def tag(self, name=None, compile_function=None): 761 if name == None and compile_function == None: 762 # @register.tag() 763 return self.tag_function 764 elif name != None and compile_function == None: 765 if(callable(name)): 766 # @register.tag 767 return self.tag_function(name) 768 else: 769 # @register.tag('somename') or @register.tag(name='somename') 770 def dec(func): 771 return self.tag(name, func) 772 return dec 773 elif name != None and compile_function != None: 774 # register.tag('somename', somefunc) 775 self.tags[name] = compile_function 776 return compile_function 777 else: 778 raise InvalidTemplateLibrary, "Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function) 819 class SimpleNodeFactory(object): 820 def __init__(self, func, takes_context=False, takes_block=False): 821 self.func = func 822 self.__doc__ = func.__doc__ 823 self.takes_context = takes_context 824 self.takes_block = takes_block 779 825 780 def tag_function(self,func): 781 self.tags[func.__name__] = func 782 return func 826 def __call__(self, parser, token): 827 tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents) 828 block_nodelist = None 829 if self.takes_block: 830 block_nodelist = parser.parse(('end' + tag_name,)) 831 parser.delete_first_token() 832 return SimpleNode(self.func, self.takes_context, block_nodelist, args_to_resolve, kwds_to_resolve) 783 833 784 def filter(self, name=None, filter_func=None): 785 if name == None and filter_func == None: 786 # @register.filter() 787 return self.filter_function 788 elif filter_func == None: 789 if(callable(name)): 790 # @register.filter 791 return self.filter_function(name) 792 else: 793 # @register.filter('somename') or @register.filter(name='somename') 794 def dec(func): 795 return self.filter(name, func) 796 return dec 797 elif name != None and filter_func != None: 798 # register.filter('somename', somefunc) 799 self.filters[name] = filter_func 800 return filter_func 801 else: 802 raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r, %r)", (name, compile_function, has_arg) 834 class InclusionNode(Node): 835 def __init__(self, func, template, context_class, takes_context, args_to_resolve, kwds_to_resolve): 836 self.func = func 837 self.template = template 838 self.context_class = context_class 839 self.takes_context = takes_context 840 self.args_to_resolve = args_to_resolve 841 self.kwds_to_resolve = kwds_to_resolve 803 842 804 def filter_function(self, func): 805 self.filters[func.__name__] = func 806 return func 843 def render(self, context): 844 resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve) 845 if self.takes_context: 846 resolved_args.insert(0, context) 847 if not getattr(self, 'nodelist', None): 848 from django.template.loader import get_template 849 t = get_template(self.template) 850 self.nodelist = t.nodelist 851 context = self.context_class(self.func(*resolved_args, **resolved_kwds)) 852 return self.nodelist.render(context) 807 853 808 def simple_tag(self,func): 809 (params, xx, xxx, defaults) = getargspec(func) 854 class InclusionNodeFactory(object): 855 def __init__(self, func, template, context_class=Context, takes_context=False): 856 self.func = func 857 self.__doc__ = func.__doc__ 858 self.template = template 859 self.context_class = context_class 860 self.takes_context = takes_context 810 861 811 class SimpleNode(Node):812 def __init__(self, vars_to_resolve):813 self.vars_to_resolve = vars_to_resolve862 def __call__(self, parser, token): 863 tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents) 864 return InclusionNode(self.func, self.template, self.context_class, self.takes_context, args_to_resolve, kwds_to_resolve) 814 865 815 def render(self, context): 816 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 817 return func(*resolved_vars) 866 class Library(object): 867 def __init__(self): 868 self.filters = {} 869 self.tags = {} 818 870 819 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode) 820 compile_func.__doc__ = func.__doc__ 821 self.tag(func.__name__, compile_func) 822 return func 871 def tag(self, func=None, name=None): 872 if callable(func): 873 self.tags[name or func.__name__] = func 874 return func 875 elif func is None: 876 return curry(self.tag, name=name) 877 raise InvalidTemplateLibrary("Unsupported argument to Library.tag: (%r)" % (func,)) 823 878 824 def inclusion_tag(self, file_name, context_class=Context, takes_context=False): 825 def dec(func): 826 (params, xx, xxx, defaults) = getargspec(func) 827 if takes_context: 828 if params[0] == 'context': 829 params = params[1:] 830 else: 831 raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'" 879 def filter(self, func=None, name=None): 880 if callable(func): 881 self.filters[name or func.__name__] = func 882 return func 883 elif func is None: 884 return curry(self.filter, name=name) 885 raise InvalidTemplateLibrary("Unsupported argument to Library.filter: (%r)" % (func,)) 832 886 833 class InclusionNode(Node): 834 def __init__(self, vars_to_resolve): 835 self.vars_to_resolve = vars_to_resolve 887 def simple_tag(self, func=None, takes_context=False, takes_block=False, name=None): 888 if callable(func): 889 self.tags[name or func.__name__] = SimpleNodeFactory(func, takes_context, takes_block) 890 return func 891 elif func is None: 892 return curry(self.simple_tag, takes_context=takes_context, takes_block=takes_block, name=name) 893 raise InvalidTemplateLibrary("Unsupported argument to Library.simple_tag: (%r)" % (func,)) 836 894 837 def render(self, context): 838 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 839 if takes_context: 840 args = [context] + resolved_vars 841 else: 842 args = resolved_vars 843 844 dict = func(*args) 845 846 if not getattr(self, 'nodelist', False): 847 from django.template.loader import get_template 848 t = get_template(file_name) 849 self.nodelist = t.nodelist 850 return self.nodelist.render(context_class(dict)) 851 852 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode) 853 compile_func.__doc__ = func.__doc__ 854 self.tag(func.__name__, compile_func) 895 def inclusion_tag(self, func=None, template=None, context_class=Context, takes_context=False, name=None): 896 if callable(func): 897 self.tags[name or func.__name__] = InclusionNodeFactory(func, template, context_class, takes_context) 855 898 return func 856 return dec 899 elif func is None: 900 return curry(self.inclusion_tag, template=template, context_class=context_class, takes_context=takes_context, name=name) 901 raise InvalidTemplateLibrary("Unsupported argument to Library.inclusion_tag: (%r)" % (func,)) 857 902 858 903 def get_library(module_name): 859 904 lib = libraries.get(module_name, None) -
django/template/context.py
=== django/template/context.py ==================================================================
37 37 for d in self.dicts: 38 38 if d.has_key(key): 39 39 return d[key] 40 r eturn settings.TEMPLATE_STRING_IF_INVALID40 raise KeyError("Context key not found: %s" % key) 41 41 42 42 def __delitem__(self, key): 43 43 "Delete a variable from the current context" … … 49 49 return True 50 50 return False 51 51 52 def get(self, key, otherwise ):52 def get(self, key, otherwise=None): 53 53 for d in self.dicts: 54 54 if d.has_key(key): 55 55 return d[key] -
django/template/defaultfilters.py
=== django/template/defaultfilters.py ==================================================================
469 469 register.filter(removetags) 470 470 register.filter(random) 471 471 register.filter(rjust) 472 register.filter( 'slice', slice_)472 register.filter(slice_, name='slice') 473 473 register.filter(slugify) 474 474 register.filter(stringformat) 475 475 register.filter(striptags) -
django/template/defaulttags.py
=== django/template/defaulttags.py ==================================================================
45 45 46 46 def render(self, context): 47 47 for var in self.vars: 48 value = resolve_variable(var, context) 48 try: 49 value = resolve_variable(var, context) 50 except VariableDoesNotExist: 51 continue 49 52 if value: 50 53 return str(value) 51 54 return '' … … 142 145 return "<IfEqualNode>" 143 146 144 147 def render(self, context): 145 val1 = resolve_variable(self.var1, context) 146 val2 = resolve_variable(self.var2, context) 148 try: 149 val1 = resolve_variable(self.var1, context) 150 except VariableDoesNotExist: 151 val1 = None 152 try: 153 val2 = resolve_variable(self.var2, context) 154 except VariableDoesNotExist: 155 val2 = None 147 156 if (self.negate and val1 != val2) or (not self.negate and val1 == val2): 148 157 return self.nodelist_true.render(context) 149 158 return self.nodelist_false.render(context) … … 187 196 188 197 def render(self, context): 189 198 obj_list = self.target.resolve(context) 190 if obj_list == '': # target_var wasn't found in context; fail silently199 if obj_list is None: 191 200 context[self.var_name] = [] 192 201 return '' 193 202 output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} … … 391 400 nodelist = parser.parse(('endfilter',)) 392 401 parser.delete_first_token() 393 402 return FilterNode(filter_expr, nodelist) 394 filter = register.tag( "filter", do_filter)403 filter = register.tag(do_filter, name='filter') 395 404 396 405 #@register.tag 397 406 def firstof(parser, token): … … 469 478 nodelist_loop = parser.parse(('endfor',)) 470 479 parser.delete_first_token() 471 480 return ForNode(loopvar, sequence, reversed, nodelist_loop) 472 do_for = register.tag( "for", do_for)481 do_for = register.tag(do_for, name='for') 473 482 474 483 def do_ifequal(parser, token, negate): 475 484 """ … … 579 588 else: 580 589 nodelist_false = NodeList() 581 590 return IfNode(boolvars, nodelist_true, nodelist_false) 582 do_if = register.tag( "if", do_if)591 do_if = register.tag(do_if, name='if') 583 592 584 593 #@register.tag 585 594 def ifchanged(parser, token): -
django/template/loader_tags.py
=== django/template/loader_tags.py ==================================================================
169 169 return ConstantIncludeNode(path[1:-1]) 170 170 return IncludeNode(bits[1]) 171 171 172 register.tag( 'block', do_block)173 register.tag( 'extends', do_extends)174 register.tag( 'include', do_include)172 register.tag(do_block, name='block') 173 register.tag(do_extends, name='extends') 174 register.tag(do_include, name='include') -
django/templatetags/i18n.py
=== django/templatetags/i18n.py ==================================================================
215 215 216 216 return BlockTranslateNode(extra_context, singular, plural, countervar, counter) 217 217 218 register.tag( 'get_available_languages', do_get_available_languages)219 register.tag( 'get_current_language', do_get_current_language)220 register.tag( 'trans', do_translate)221 register.tag( 'blocktrans', do_block_translate)218 register.tag(do_get_available_languages, name='get_available_languages') 219 register.tag(do_get_current_language, name='get_current_language') 220 register.tag(do_translate, name='trans') 221 register.tag(do_block_translate, name='blocktrans') -
docs/templates_python.txt
=== docs/templates_python.txt ==================================================================
561 561 Most filters don't take arguments. In this case, just leave the argument out of 562 562 your function. Example:: 563 563 564 def lower(value): # Only one argument.564 def do_lower(value): # Only one argument. 565 565 "Converts a string into all lowercase" 566 566 return value.lower() 567 567 568 568 When you've written your filter definition, you need to register it with 569 569 your ``Library`` instance, to make it available to Django's template language:: 570 570 571 register.filter( 'cut',cut)572 register.filter( 'lower', lower)571 register.filter(cut) 572 register.filter(do_lower, name='lower') 573 573 574 The ``Library.filter()`` method takes t woarguments:574 The ``Library.filter()`` method takes the following arguments: 575 575 576 1. The name of the filter -- a string. 577 2. The compilation function -- a Python function (not the name of the 576 1. The filter function -- a Python function (not the name of the 578 577 function as a string). 578 2. An optional alternative name for the filter -- a string). By default 579 it is the same as the function name. 579 580 580 581 If you're using Python 2.4 or above, you can use ``register.filter()`` as a 581 582 decorator instead:: 582 583 583 @register.filter (name='cut')584 @register.filter 584 585 def cut(value, arg): 585 586 return value.replace(arg, '') 586 587 587 @register.filter 588 def lower(value):588 @register.filter(name=lower) 589 def do_lower(value): 589 590 return value.lower() 590 591 591 If you leave off the ``name`` argument, as in the second example above, Django592 will use the function's name as the filter name.592 If you use the filter decorator without the ``name`` argument, as in the first 593 example above, Django will use the function's name as the filter name. 593 594 594 595 Writing custom template tags 595 596 ---------------------------- … … 709 710 Finally, register the tag with your module's ``Library`` instance, as explained 710 711 in "Writing custom template filters" above. Example:: 711 712 712 register.tag( 'current_time', do_current_time)713 register.tag(do_current_time, name='current_time') 713 714 714 715 The ``tag()`` method takes two arguments: 715 716 716 1. The name of the template tag -- a string. If this is left out, the 717 name of the compilation function will be used. 718 2. The compilation function -- a Python function (not the name of the 717 1. The tag function -- a Python function (not the name of the 719 718 function as a string). 719 2. An optional alternative name for the template tag -- a string. If this 720 is left out, the name of the tag function will be used. 720 721 721 722 As with filter registration, it is also possible to use this as a decorator, in 722 723 Python 2.4 and above:: -
tests/othertests/templates.py
=== tests/othertests/templates.py ==================================================================
1 1 from django.conf import settings 2 settings.TEMPLATE_STRING_IF_INVALID = "[undefined]" 2 3 3 4 4 from django import template 5 5 from django.template import loader 6 6 from django.utils.translation import activate, deactivate, install … … 23 23 def do_echo(parser, token): 24 24 return EchoNode(token.contents.split()[1:]) 25 25 26 register.tag( "echo", do_echo)26 register.tag(do_echo, name='echo') 27 27 28 28 template.libraries['django.templatetags.testtags'] = register 29 29 … … 73 73 'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"), 74 74 75 75 # Fail silently when a variable is not found in the current context 76 'basic-syntax04': ("as{{ missing }}df", {}, "as df"),76 'basic-syntax04': ("as{{ missing }}df", {}, "as%sdf" % settings.TEMPLATE_STRING_IF_INVALID), 77 77 78 78 # A variable may not contain more than one word 79 79 'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError), … … 89 89 'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"), 90 90 91 91 # Fail silently when a variable's attribute isn't found 92 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, " "),92 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 93 93 94 94 # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore 95 95 'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError), … … 105 105 'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"), 106 106 107 107 # Fail silently when a variable's dictionary key isn't found 108 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, " "),108 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 109 109 110 110 # Fail silently when accessing a non-simple method 111 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, " "),111 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 112 112 113 113 # Basic filter usage 114 114 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), … … 147 147 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), 148 148 149 149 # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute 150 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1 2"),150 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1%s2" % settings.TEMPLATE_STRING_IF_INVALID), 151 151 152 152 # In methods that raise an exception without a "silent_variable_attribute" set to True, 153 153 # the exception propogates -
tests/othertests/tokenize_tag_contents.py
=== tests/othertests/tokenize_tag_contents.py ==================================================================
1 """ 2 # positional argument 3 >>> tok('tag arg1') 4 ('tag', ['arg1'], {}) 5 6 # single-quoted positional argument 7 >>> tok("tag 'arg1 with spaces'") 8 ('tag', ["'arg1 with spaces'"], {}) 9 10 # double-quoted positional argument 11 >>> tok('tag "arg1 with spaces"') 12 ('tag', ['"arg1 with spaces"'], {}) 13 14 # named argument 15 >>> tok('tag name1=arg1') 16 ('tag', [], {'name1': 'arg1'}) 17 18 # single-quoted named argument 19 >>> tok("tag name1='arg1 with spaces'") 20 ('tag', [], {'name1': "'arg1 with spaces'"}) 21 22 # double-quoted named argument 23 >>> tok('tag name1="arg1 with spaces"') 24 ('tag', [], {'name1': '"arg1 with spaces"'}) 25 26 # positional argument and named argument 27 >>> tok('tag arg1 name1=arg2') 28 ('tag', ['arg1'], {'name1': 'arg2'}) 29 30 # mixed arguments 31 >>> tok('tag arg1 "arg2 with spaces" name1=arg3 name2="arg4 with spaces"') 32 ('tag', ['arg1', '"arg2 with spaces"'], {'name2': '"arg4 with spaces"', 'name1': 'arg3'}) 33 34 # double quotes in single-quoted string 35 >>> tok("tag 'arg1 \\"with quotes\\"'") 36 ('tag', ['\\'arg1 "with quotes"\\''], {}) 37 38 # single quotes in double-quoted string 39 >>> tok('tag "arg1 \\'with quotes\\'"') 40 ('tag', ['"arg1 \\'with quotes\\'"'], {}) 41 42 # single quotes in single-quoted string 43 >>> tok("tag 'arg1 \\\\'with quotes\\\\''") 44 ('tag', ["'arg1 'with quotes''"], {}) 45 46 # double quotes in double-quoted string 47 >>> tok('tag "arg1 \\\\"with quotes\\\\""') 48 ('tag', ['"arg1 "with quotes""'], {}) 49 50 # positional argument after named argument not allowed 51 >>> tok('tag name1=arg1 arg2') 52 Traceback (most recent call last): 53 ... 54 SyntaxError: template tag syntax error: non-keyword arguments must come before keyword arguments 55 56 """ 57 58 from django.template import tokenize_tag_contents as tok 59 60 if __name__ == "__main__": 61 import doctest 62 doctest.testmod()