Ticket #1400: templates_r2388.diff
File templates_r2388.diff, 37.7 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')(pagination)68 pagination = register.inclusion_tag(pagination, 'admin/pagination') 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")(result_list)188 result_list = register.inclusion_tag(result_list, 'admin/change_list_results') 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')(date_hierarchy)248 date_hierarchy = register.inclusion_tag(date_hierarchy, 'admin/date_hierarchy') 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')(search_form)256 search_form = register.inclusion_tag(search_form, 'admin/search_form') 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')(filter)260 filter = register.inclusion_tag(filter, 'admin/filter') 261 261 262 262 def filters(cl): 263 263 return {'cl': cl} 264 filters = register.inclusion_tag( 'admin/filters')(filters)264 filters = register.inclusion_tag(filters, 'admin/filters') -
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, 36 36 'show_save': True 37 37 } 38 submit_row = register.inclusion_tag( 'admin/submit_line', takes_context=True)(submit_row)38 submit_row = register.inclusion_tag(submit_row, 'admin/submit_line', 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', takes_context=True)(admin_field_line)232 admin_field_line = register.inclusion_tag(admin_field_line, 'admin/field_line', 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 ==================================================================
315 315 return CommentListNode(package, module, var_name, obj_id, tokens[5], self.free, ordering) 316 316 317 317 # registration comments 318 register.tag( 'get_comment_list', DoGetCommentList(False))319 register.tag( 'comment_form', DoCommentForm(False))320 register.tag( 'get_comment_count', DoCommentCount(False))318 register.tag(DoGetCommentList(False), name='get_comment_list') 319 register.tag(DoCommentForm(False), name='comment_form') 320 register.tag(DoCommentCount(False), name='get_comment_count') 321 321 # free comments 322 register.tag( 'get_free_comment_list', DoGetCommentList(True))323 register.tag( 'free_comment_form', DoCommentForm(True))324 register.tag( 'get_free_comment_count', DoCommentCount(True))322 register.tag(DoGetCommentList(True), name='get_free_comment_list') 323 register.tag(DoCommentForm(True), name='free_comment_form') 324 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) … … 227 229 elif token.token_type == TOKEN_VAR: 228 230 if not token.contents: 229 231 self.empty_variable(token) 230 filter_expression = self.compile_filter(token.contents )232 filter_expression = self.compile_filter(token.contents, default=settings.TEMPLATE_STRING_IF_INVALID) 231 233 var_node = self.create_variable_node(filter_expression) 232 234 self.extend_nodelist(nodelist, var_node,token) 233 235 elif token.token_type == TOKEN_BLOCK: … … 309 311 self.tags.update(lib.tags) 310 312 self.filters.update(lib.filters) 311 313 312 def compile_filter(self, token):314 def compile_filter(self, token, default=None): 313 315 "Convenient wrapper for FilterExpression" 314 return FilterExpression(token, self )316 return FilterExpression(token, self, default) 315 317 316 318 def find_filter(self, filter_name): 317 319 if self.filters.has_key(filter_name): … … 496 498 This class should never be instantiated outside of the 497 499 get_filters_from_token helper function. 498 500 """ 499 def __init__(self, token, parser ):501 def __init__(self, token, parser, default=None): 500 502 self.token = token 501 matches = filter_re.finditer(token)503 self.default = default 502 504 var = None 503 505 filters = [] 504 506 upto = 0 505 for match in matches:507 for match in filter_re.finditer(token): 506 508 start = match.start() 507 509 if upto != start: 508 510 raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s" % \ … … 534 536 upto = match.end() 535 537 if upto != len(token): 536 538 raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] 537 self.var 539 self.var, self.filters = var, filters 538 540 539 541 def resolve(self, context): 540 542 try: 541 543 obj = resolve_variable(self.var, context) 542 544 except VariableDoesNotExist: 543 obj = settings.TEMPLATE_STRING_IF_INVALID545 return self.default 544 546 for func, args in self.filters: 545 547 arg_vals = [] 546 548 for lookup, arg in args: … … 588 590 """ 589 591 Returns the resolved variable, which may contain attribute syntax, within 590 592 the given context. The variable may be a hard-coded string (if it begins 591 and ends with single or double quote marks). 593 and ends with single or double quote marks), a boolean literal, or an 594 integer or float literal. 592 595 593 596 >>> c = {'article': {'section':'News'}} 594 597 >>> resolve_variable('article.section', c) … … 604 607 605 608 (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 606 609 """ 607 if path[0] in '0123456789':610 if path[0].isdigit(): 608 611 number_type = '.' in path and float or int 609 try: 610 current = number_type(path) 611 except ValueError: 612 current = settings.TEMPLATE_STRING_IF_INVALID 613 elif path[0] in ('"', "'") and path[0] == path[-1]: 614 current = path[1:-1] 615 else: 616 current = context 617 bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) 618 while bits: 619 try: # dictionary lookup 620 current = current[bits[0]] 621 except (TypeError, AttributeError, KeyError): 622 try: # attribute lookup 623 current = getattr(current, bits[0]) 624 if callable(current): 625 if getattr(current, 'alters_data', False): 626 current = settings.TEMPLATE_STRING_IF_INVALID 627 else: 628 try: # method call (assuming no args required) 629 current = current() 630 except TypeError: # arguments *were* required 631 # GOTCHA: This will also catch any TypeError 632 # raised in the function itself. 633 current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call 634 except Exception, e: 635 if getattr(e, 'silent_variable_failure', False): 636 current = settings.TEMPLATE_STRING_IF_INVALID 637 else: 638 raise 639 except (TypeError, AttributeError): 640 try: # list-index lookup 641 current = current[int(bits[0])] 642 except (IndexError, ValueError, KeyError): 643 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bits[0], current) # missing attribute 644 del bits[0] 645 return current 612 return number_type(path) 613 if path in BOOLEANS: 614 return bool(BOOLEANS.index(path)) 615 if path[0] in ('"', "'"): 616 if path[0] == path[-1]: 617 return path[1:-1] 618 raise VariableDoesNotExist, "Missing quotes in string literal %s" % (path,) 619 for bit in path.split(VARIABLE_ATTRIBUTE_SEPARATOR): 620 try: # dictionary lookup 621 context = context[bit] 622 except (TypeError, AttributeError, KeyError): 623 try: # attribute lookup 624 context = getattr(context, bit) 625 except (TypeError, AttributeError): 626 try: # list-index lookup 627 context = context[int(bit)] 628 except (IndexError, ValueError, KeyError): 629 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute 630 else: 631 if callable(context): 632 if getattr(context, 'alters_data', False): 633 raise VariableDoesNotExist("Failed lookup for key [%s] in %r" % (bit, context)) 634 try: # method call (assuming no args required) 635 context = context() 636 except Exception, e: 637 if getattr(e, 'silent_variable_failure', False): 638 raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute 639 raise 640 return context 646 641 642 tag_tokens_re = re.compile(r""" 643 (?:\s*) # ignore preceeding whitespace 644 ( # token group 645 (?:[A-Za-z_][0-9A-Za-z_]*=)?" # optional name and open double-quote 646 [^"\\]* # normal characters 647 (?:\\. # chew up backslash and following char 648 (?:|[^"\\])* # normal characters 649 )* # repeat as needed to chew up the backslashes 650 " # close double-quote 651 | 652 (?:[A-Za-z_][0-9A-Za-z_]*=)?' # optional name and open single-quote 653 [^'\\]* # normal characters 654 (?:\\. # chew up backslash and following char 655 (?:|[^'\\])* # normal characters 656 )* # repeat as needed to chew up the backslashes 657 ' # close single-quote 658 | 659 (?:[A-Za-z_][0-9A-Za-z_]*=)? # optional name 660 [^"'\s][^\s]* # unquoted token 661 ) 662 (?:\s+|$) # chew up following ws until next token 663 """, re.VERBOSE) 664 665 def tokenize_tag_contents(contents): 666 667 """ Parse tag contents into (tag_name, args_to_resolve, kwds_to_resolve). 668 If an argument name is a Python keyword append an underscore. 669 670 >>> tokenize_tag_contents("An 'easy' one.") 671 ('An', ["'easy'", 'one.'], {}) 672 >>> tokenize_tag_contents(r'''Please don't try 'thi\\'s at' named="hom\\"e."''') 673 ('Please', ["don't", 'try', "'thi\'s at'"], {'named': '"hom\\\\"e."'}) 674 """ 675 676 bits = [] 677 i, n = 0, len(contents) 678 while i < n: 679 m = tag_tokens_re.match(contents, i) 680 if not m: 681 raise ValueError("Can't parse string %s at index %s" %(repr(contents), i)) 682 bit = m.group(1) 683 if bit.startswith('"'): 684 bit = bit.replace('\\"', '"') 685 elif bit.startswith("'"): 686 bit = bit.replace("\\'", "'") 687 bits.append(bit) 688 i = m.end() 689 tag_name = bits[0] 690 args_to_resolve = [] 691 kwds_to_resolve = {} 692 for bit in bits[1:]: 693 if bit[0] in ("'", '"'): 694 if kwds_to_resolve: 695 raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments") 696 args_to_resolve.append(bit) 697 else: 698 try: 699 name, value = bit.split('=', 1) 700 if keyword.iskeyword(name): 701 name += '_' 702 kwds_to_resolve[name] = value 703 except ValueError: 704 if kwds_to_resolve: 705 raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments") 706 args_to_resolve.append(bit) 707 return tag_name, args_to_resolve, kwds_to_resolve 708 709 def resolve_tag_arguments(context, args_to_resolve, kwds_to_resolve): 710 resolved_args = [resolve_variable(var, context) for var in args_to_resolve] 711 resolved_kwds = dict([(name, resolve_variable(var, context)) for name, var in kwds_to_resolve.items()]) 712 return resolved_args, resolved_kwds 713 647 714 class Node: 648 715 def render(self, context): 649 716 "Return the node rendered as a string" … … 737 804 raise 738 805 return self.encode_output(output) 739 806 740 def generic_tag_compiler(params, defaults, name, node_class, parser, token): 741 "Returns a template.Node subclass." 742 bits = token.contents.split()[1:] 743 bmax = len(params) 744 def_len = defaults and len(defaults) or 0 745 bmin = bmax - def_len 746 if(len(bits) < bmin or len(bits) > bmax): 747 if bmin == bmax: 748 message = "%s takes %s arguments" % (name, bmin) 749 else: 750 message = "%s takes between %s and %s arguments" % (name, bmin, bmax) 751 raise TemplateSyntaxError, message 752 return node_class(bits) 807 class SimpleNode(Node): 808 def __init__(self, func, takes_context, block_nodelist, args_to_resolve, kwds_to_resolve): 809 self.func = func 810 self.takes_context = takes_context 811 self.block_nodelist = block_nodelist 812 self.args_to_resolve = args_to_resolve 813 self.kwds_to_resolve = kwds_to_resolve 753 814 754 class Library(object): 755 def __init__(self): 756 self.filters = {} 757 self.tags = {} 815 def render(self, context): 816 resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve) 817 if self.block_nodelist: 818 resolved_args.insert(0, self.block_nodelist) 819 if self.takes_context: 820 resolved_args.insert(0, context) 821 return self.func(*resolved_args, **resolved_kwds) or '' 758 822 759 def tag(self, name=None, compile_function=None): 760 if name == None and compile_function == None: 761 # @register.tag() 762 return self.tag_function 763 elif name != None and compile_function == None: 764 if(callable(name)): 765 # @register.tag 766 return self.tag_function(name) 767 else: 768 # @register.tag('somename') or @register.tag(name='somename') 769 def dec(func): 770 return self.tag(name, func) 771 return dec 772 elif name != None and compile_function != None: 773 # register.tag('somename', somefunc) 774 self.tags[name] = compile_function 775 return compile_function 776 else: 777 raise InvalidTemplateLibrary, "Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function) 823 class SimpleNodeFactory(object): 824 def __init__(self, func, takes_context=False, takes_block=False): 825 self.func = func 826 self.__doc__ = func.__doc__ 827 self.takes_context = takes_context 828 self.takes_block = takes_block 778 829 779 def tag_function(self,func): 780 self.tags[func.__name__] = func 781 return func 830 def __call__(self, parser, token): 831 tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents) 832 block_nodelist = None 833 if self.takes_block: 834 block_nodelist = parser.parse(('end' + tag_name,)) 835 parser.delete_first_token() 836 return SimpleNode(self.func, self.takes_context, block_nodelist, args_to_resolve, kwds_to_resolve) 782 837 783 def filter(self, name=None, filter_func=None): 784 if name == None and filter_func == None: 785 # @register.filter() 786 return self.filter_function 787 elif filter_func == None: 788 if(callable(name)): 789 # @register.filter 790 return self.filter_function(name) 791 else: 792 # @register.filter('somename') or @register.filter(name='somename') 793 def dec(func): 794 return self.filter(name, func) 795 return dec 796 elif name != None and filter_func != None: 797 # register.filter('somename', somefunc) 798 self.filters[name] = filter_func 799 return filter_func 800 else: 801 raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r, %r)", (name, compile_function, has_arg) 838 class InclusionNode(Node): 839 def __init__(self, func, template, context_class, takes_context, args_to_resolve, kwds_to_resolve): 840 self.func = func 841 self.template = template 842 self.context_class = context_class 843 self.takes_context = takes_context 844 self.args_to_resolve = args_to_resolve 845 self.kwds_to_resolve = kwds_to_resolve 802 846 803 def filter_function(self, func): 804 self.filters[func.__name__] = func 805 return func 847 def render(self, context): 848 resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve) 849 if self.takes_context: 850 resolved_args.insert(0, context) 851 if not getattr(self, 'nodelist', None): 852 from django.template.loader import get_template 853 t = get_template(self.template) 854 self.nodelist = t.nodelist 855 context = self.context_class(self.func(*resolved_args, **resolved_kwds)) 856 return self.nodelist.render(context) 806 857 807 def simple_tag(self,func): 808 (params, xx, xxx, defaults) = getargspec(func) 858 class InclusionNodeFactory(object): 859 def __init__(self, func, template, context_class=Context, takes_context=False): 860 self.func = func 861 self.__doc__ = func.__doc__ 862 self.template = template 863 self.context_class = context_class 864 self.takes_context = takes_context 809 865 810 class SimpleNode(Node):811 def __init__(self, vars_to_resolve):812 self.vars_to_resolve = vars_to_resolve866 def __call__(self, parser, token): 867 tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents) 868 return InclusionNode(self.func, self.template, self.context_class, self.takes_context, args_to_resolve, kwds_to_resolve) 813 869 814 def render(self, context): 815 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 816 return func(*resolved_vars) 870 class Library(object): 871 def __init__(self): 872 self.filters = {} 873 self.tags = {} 817 874 818 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode) 819 compile_func.__doc__ = func.__doc__ 820 self.tag(func.__name__, compile_func) 821 return func 875 def tag(self, func=None, name=None): 876 if callable(func): 877 self.tags[name or func.__name__] = func 878 return func 879 elif func is None: 880 return curry(self.tag, name=name) 881 raise InvalidTemplateLibrary("Unsupported argument to Library.tag: (%r)" % (func,)) 822 882 823 def inclusion_tag(self, file_name, context_class=Context, takes_context=False): 824 def dec(func): 825 (params, xx, xxx, defaults) = getargspec(func) 826 if takes_context: 827 if params[0] == 'context': 828 params = params[1:] 829 else: 830 raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'" 883 def filter(self, func=None, name=None): 884 if callable(func): 885 self.filters[name or func.__name__] = func 886 return func 887 elif func is None: 888 return curry(self.filter, name=name) 889 raise InvalidTemplateLibrary("Unsupported argument to Library.filter: (%r)" % (func,)) 831 890 832 class InclusionNode(Node): 833 def __init__(self, vars_to_resolve): 834 self.vars_to_resolve = vars_to_resolve 891 def simple_tag(self, func=None, takes_context=False, takes_block=False, name=None): 892 if callable(func): 893 self.tags[name or func.__name__] = SimpleNodeFactory(func, takes_context, takes_block) 894 return func 895 elif func is None: 896 return curry(self.simple_tag, takes_context=takes_context, takes_block=takes_block, name=name) 897 raise InvalidTemplateLibrary("Unsupported argument to Library.simple_tag: (%r)" % (func,)) 835 898 836 def render(self, context): 837 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] 838 if takes_context: 839 args = [context] + resolved_vars 840 else: 841 args = resolved_vars 842 843 dict = func(*args) 844 845 if not getattr(self, 'nodelist', False): 846 from django.template.loader import get_template 847 t = get_template(file_name) 848 self.nodelist = t.nodelist 849 return self.nodelist.render(context_class(dict)) 850 851 compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode) 852 compile_func.__doc__ = func.__doc__ 853 self.tag(func.__name__, compile_func) 899 def inclusion_tag(self, func=None, template=None, context_class=Context, takes_context=False, name=None): 900 if callable(func): 901 self.tags[name or func.__name__] = InclusionNodeFactory(func, template, context_class, takes_context) 854 902 return func 855 return dec 903 elif func is None: 904 return curry(self.inclusion_tag, template=template, context_class=context_class, takes_context=takes_context, name=name) 905 raise InvalidTemplateLibrary("Unsupported argument to Library.inclusion_tag: (%r)" % (func,)) 856 906 857 907 def get_library(module_name): 858 908 lib = libraries.get(module_name, None) -
django/template/context.py
=== django/template/context.py ==================================================================
33 33 for dict in self.dicts: 34 34 if dict.has_key(key): 35 35 return dict[key] 36 r eturn settings.TEMPLATE_STRING_IF_INVALID36 raise KeyError("Context key not found: %s" % key) 37 37 38 38 def __delitem__(self, key): 39 39 "Delete a variable from the current context" … … 45 45 return True 46 46 return False 47 47 48 def get(self, key, otherwise ):48 def get(self, key, otherwise=None): 49 49 for dict in self.dicts: 50 50 if dict.has_key(key): 51 51 return dict[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 ==================================================================
167 167 return ConstantIncludeNode(path[1:-1]) 168 168 return IncludeNode(bits[1]) 169 169 170 register.tag( 'block', do_block)171 register.tag( 'extends', do_extends)172 register.tag( 'include', do_include)170 register.tag(do_block, name='block') 171 register.tag(do_extends, name='extends') 172 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 ==================================================================
566 566 Most filters don't take arguments. In this case, just leave the argument out of 567 567 your function. Example:: 568 568 569 def lower(value): # Only one argument.569 def do_lower(value): # Only one argument. 570 570 "Converts a string into all lowercase" 571 571 return value.lower() 572 572 573 573 When you've written your filter definition, you need to register it with 574 574 your ``Library`` instance, to make it available to Django's template language:: 575 575 576 register.filter( 'cut',cut)577 register.filter( 'lower', lower)576 register.filter(cut) 577 register.filter(do_lower, name='lower') 578 578 579 The ``Library.filter()`` method takes t woarguments:579 The ``Library.filter()`` method takes the following arguments: 580 580 581 1. The name of the filter -- a string. 582 2. The compilation function -- a Python function (not the name of the 581 1. The filter function -- a Python function (not the name of the 583 582 function as a string). 583 2. An optional alternative name for the filter -- a string). By default 584 it is the same as the function name. 584 585 585 586 If you're using Python 2.4 or above, you can use ``register.filter()`` as a 586 587 decorator instead:: 587 588 588 @register.filter (name='cut')589 @register.filter 589 590 def cut(value, arg): 590 591 return value.replace(arg, '') 591 592 592 @register.filter 593 def lower(value):593 @register.filter(name=lower) 594 def do_lower(value): 594 595 return value.lower() 595 596 596 If you leave off the ``name`` argument, as in the second example above, Django597 will use the function's name as the filter name.597 If you use the filter decorator without the ``name`` argument, as in the first 598 example above, Django will use the function's name as the filter name. 598 599 599 600 Writing custom template tags 600 601 ---------------------------- … … 714 715 Finally, register the tag with your module's ``Library`` instance, as explained 715 716 in "Writing custom template filters" above. Example:: 716 717 717 register.tag( 'current_time', do_current_time)718 register.tag(do_current_time, name='current_time') 718 719 719 720 The ``tag()`` method takes two arguments: 720 721 721 1. The name of the template tag -- a string. If this is left out, the 722 name of the compilation function will be used. 723 2. The compilation function -- a Python function (not the name of the 722 1. The tag function -- a Python function (not the name of the 724 723 function as a string). 724 2. An optional alternative name for the template tag -- a string. If this 725 is left out, the name of the tag function will be used. 725 726 726 727 As with filter registration, it is also possible to use this as a decorator, in 727 728 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 … … 22 22 def do_echo(parser, token): 23 23 return EchoNode(token.contents.split()[1:]) 24 24 25 register.tag( "echo", do_echo)25 register.tag(do_echo, name='echo') 26 26 27 27 template.libraries['django.templatetags.testtags'] = register 28 28 … … 72 72 'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"), 73 73 74 74 # Fail silently when a variable is not found in the current context 75 'basic-syntax04': ("as{{ missing }}df", {}, "as df"),75 'basic-syntax04': ("as{{ missing }}df", {}, "as%sdf" % settings.TEMPLATE_STRING_IF_INVALID), 76 76 77 77 # A variable may not contain more than one word 78 78 'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError), … … 88 88 'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"), 89 89 90 90 # Fail silently when a variable's attribute isn't found 91 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, " "),91 'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 92 92 93 93 # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore 94 94 'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError), … … 104 104 'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"), 105 105 106 106 # Fail silently when a variable's dictionary key isn't found 107 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, " "),107 'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 108 108 109 109 # Fail silently when accessing a non-simple method 110 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, " "),110 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID), 111 111 112 112 # Basic filter usage 113 113 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), … … 146 146 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), 147 147 148 148 # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute 149 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1 2"),149 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1%s2" % settings.TEMPLATE_STRING_IF_INVALID), 150 150 151 151 # In methods that raise an exception without a "silent_variable_attribute" set to True, 152 152 # 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()