Ticket #3453: resolve-variable-v3.diff
File resolve-variable-v3.diff, 22.2 KB (added by , 17 years ago) |
---|
-
django/templatetags/i18n.py
1 from django.template import Node, resolve_variable1 from django.template import Node, Variable 2 2 from django.template import TemplateSyntaxError, TokenParser, Library 3 3 from django.template import TOKEN_TEXT, TOKEN_VAR 4 4 from django.utils import translation … … 32 32 33 33 class TranslateNode(Node): 34 34 def __init__(self, value, noop): 35 self.value = value35 self.value = Variable(value) 36 36 self.noop = noop 37 37 38 38 def render(self, context): 39 value = resolve_variable(self.value,context)39 value = self.value.resolve(context) 40 40 if self.noop: 41 41 return value 42 42 else: -
django/contrib/comments/templatetags/comments.py
19 19 ratings_optional=False, ratings_required=False, rating_options='', 20 20 is_public=True): 21 21 self.content_type = content_type 22 if obj_id_lookup_var is not None: 23 obj_id_lookup_var = template.Variable(obj_id_lookup_var) 22 24 self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free 23 25 self.photos_optional, self.photos_required = photos_optional, photos_required 24 26 self.ratings_optional, self.ratings_required = ratings_optional, ratings_required … … 32 34 context.push() 33 35 if self.obj_id_lookup_var is not None: 34 36 try: 35 self.obj_id = template.resolve_variable(self.obj_id_lookup_var,context)37 self.obj_id = self.obj_id_lookup_var.resolve(context) 36 38 except template.VariableDoesNotExist: 37 39 return '' 38 40 # Validate that this object ID is valid for this content-type. … … 75 77 class CommentCountNode(template.Node): 76 78 def __init__(self, package, module, context_var_name, obj_id, var_name, free): 77 79 self.package, self.module = package, module 80 if context_var_name is not None: 81 context_var_name = template.Variable(context_var_name) 78 82 self.context_var_name, self.obj_id = context_var_name, obj_id 79 83 self.var_name, self.free = var_name, free 80 84 … … 82 86 from django.conf import settings 83 87 manager = self.free and FreeComment.objects or Comment.objects 84 88 if self.context_var_name is not None: 85 self.obj_id = template.resolve_variable(self.context_var_name,context)89 self.obj_id = self.context_var_name.resolve(context) 86 90 comment_count = manager.filter(object_id__exact=self.obj_id, 87 91 content_type__app_label__exact=self.package, 88 92 content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() … … 92 96 class CommentListNode(template.Node): 93 97 def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): 94 98 self.package, self.module = package, module 99 if context_var_name is not None: 100 context_var_name = template.Variable(context_var_name) 95 101 self.context_var_name, self.obj_id = context_var_name, obj_id 96 102 self.var_name, self.free = var_name, free 97 103 self.ordering = ordering … … 102 108 get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma 103 109 if self.context_var_name is not None: 104 110 try: 105 self.obj_id = template.resolve_variable(self.context_var_name,context)111 self.obj_id = self.context_var_name.resolve(context) 106 112 except template.VariableDoesNotExist: 107 113 return '' 108 114 kwargs = { -
django/contrib/admin/templatetags/admin_modify.py
72 72 default = None 73 73 74 74 def __init__(self, bound_field_var): 75 self.bound_field_var = bound_field_var75 self.bound_field_var = template.Variable(bound_field_var) 76 76 77 77 def get_nodelist(cls, klass): 78 78 if klass not in cls.nodelists: … … 96 96 get_nodelist = classmethod(get_nodelist) 97 97 98 98 def render(self, context): 99 bound_field = template.resolve_variable(self.bound_field_var,context)99 bound_field = self.bound_field_var.resolve(context) 100 100 101 101 context.push() 102 102 context['bound_field'] = bound_field … … 156 156 157 157 class EditInlineNode(template.Node): 158 158 def __init__(self, rel_var): 159 self.rel_var = rel_var159 self.rel_var = template.Variable(rel_var) 160 160 161 161 def render(self, context): 162 relation = template.resolve_variable(self.rel_var,context)162 relation = self.rel_var.resolve(context) 163 163 context.push() 164 164 if relation.field.rel.edit_inline == models.TABULAR: 165 165 bound_related_object_class = TabularBoundRelatedObject -
django/template/defaultfilters.py
1 1 "Default variable filters" 2 2 3 from django.template import resolve_variable, Library3 from django.template import Variable, Library 4 4 from django.conf import settings 5 5 from django.utils.translation import ugettext, ungettext 6 6 from django.utils.encoding import force_unicode, smart_str, iri_to_uri … … 297 297 Takes a list of dicts, returns that list sorted by the property given in 298 298 the argument. 299 299 """ 300 decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] 300 var_resolve = Variable(arg).resolve 301 decorated = [(var_resolve(item), item) for item in value] 301 302 decorated.sort() 302 303 return [item[1] for item in decorated] 303 304 … … 306 307 Takes a list of dicts, returns that list sorted in reverse order by the 307 308 property given in the argument. 308 309 """ 309 decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] 310 var_resolve = Variable(arg).resolve 311 decorated = [(var_resolve(item), item) for item in value] 310 312 decorated.sort() 311 313 decorated.reverse() 312 314 return [item[1] for item in decorated] -
django/template/__init__.py
88 88 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 89 89 re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), 90 90 re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) 91 # matches if the string is valid number92 number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')93 91 94 92 # global dictionary of libraries that have been loaded using get_library 95 93 libraries = {} … … 564 562 elif constant_arg is not None: 565 563 args.append((False, constant_arg.replace(r'\"', '"'))) 566 564 elif var_arg: 567 args.append((True, var_arg))565 args.append((True, Variable(var_arg))) 568 566 filter_func = parser.find_filter(filter_name) 569 567 self.args_check(filter_name,filter_func, args) 570 568 filters.append( (filter_func,args)) 571 569 upto = match.end() 572 570 if upto != len(token): 573 571 raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token) 574 self.var, self.filters = var, filters 572 self.filters = filters 573 self.var = Variable(var) 575 574 576 575 def resolve(self, context, ignore_failures=False): 577 576 try: 578 obj = resolve_variable(self.var,context)577 obj = self.var.resolve(context) 579 578 except VariableDoesNotExist: 580 579 if ignore_failures: 581 580 obj = None … … 595 594 if not lookup: 596 595 arg_vals.append(arg) 597 596 else: 598 arg_vals.append( resolve_variable(arg,context))597 arg_vals.append(arg.resolve(context)) 599 598 obj = func(obj, *arg_vals) 600 599 return obj 601 600 … … 637 636 def resolve_variable(path, context): 638 637 """ 639 638 Returns the resolved variable, which may contain attribute syntax, within 640 the given context. The variable may be a hard-coded string (if it begins 641 and ends with single or double quote marks). 639 the given context. 640 641 Deprecated; use the Variable class instead. 642 """ 643 return Variable(path).resolve(context) 642 644 643 >>> c = {'article': {'section':'News'}} 644 >>> resolve_variable('article.section', c) 645 u'News' 646 >>> resolve_variable('article', c) 647 {'section': 'News'} 648 >>> class AClass: pass 649 >>> c = AClass() 650 >>> c.article = AClass() 651 >>> c.article.section = 'News' 652 >>> resolve_variable('article.section', c) 653 u'News' 645 class Variable(object): 646 """ 647 A template variable, resolvable against a given context. The variable may be 648 a hard-coded string (if it begins and ends with single or double quote 649 marks):: 650 651 >>> c = {'article': {'section':'News'}} 652 >>> Variable('article.section').resolve(c) 653 u'News' 654 >>> Variable('article').resolve(c) 655 {'section': 'News'} 656 >>> class AClass: pass 657 >>> c = AClass() 658 >>> c.article = AClass() 659 >>> c.article.section = 'News' 660 >>> Variable('article.section').resolve(c) 661 u'News' 654 662 655 663 (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 656 664 """ 657 if number_re.match(path): 658 number_type = '.' in path and float or int 659 current = number_type(path) 660 elif path[0] in ('"', "'") and path[0] == path[-1]: 661 current = path[1:-1] 662 else: 665 666 def __init__(self, var): 667 self.var = var 668 self.literal = None 669 self.lookups = None 670 671 try: 672 # First try to treat this variable as a number. 673 # 674 # Note that this could cause an OverflowError here that we're not 675 # catching. Since this should only happen at compile time, that's 676 # probably OK. 677 self.literal = float(var) 678 679 # So it's a float... is it an int? If the original value contained a 680 # dot or an "e" then it was a float, not an int. 681 if '.' not in var and 'e' not in var.lower(): 682 self.literal = int(self.literal) 683 684 # "2." is invalid 685 if var.endswith('.'): 686 raise ValueError 687 688 except ValueError: 689 # A ValueError means that the variable isn't a number. 690 # If it's wrapped with quotes (single or double), then 691 # we're also dealing with a literal. 692 if var[0] in "\"'" and var[0] == var[-1]: 693 self.literal = var[1:-1] 694 695 else: 696 # Otherwise we'll set self.lookups so that resolve() knows we're 697 # dealing with a bonafide variable 698 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR)) 699 700 def resolve(self, context): 701 """Resolve this variable against a given context.""" 702 if self.lookups is not None: 703 # We're dealing with a variable that needs to be resolved 704 return self._resolve_lookup(context) 705 else: 706 # We're dealing with a literal, so it's already been "resolved" 707 return self.literal 708 709 def __repr__(self): 710 return "<%s: %r>" % (self.__class__.__name__, self.var) 711 712 def __str__(self): 713 return self.var 714 715 def _resolve_lookup(self, context): 716 """ 717 Performs resolution of a real variable (i.e. not a literal) against the 718 given context. 719 720 As indicated by the method's name, this method is an implementation 721 detail and shouldn't be called by external code. Use Variable.resolve() 722 instead. 723 """ 663 724 current = context 664 bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) 665 while bits: 725 for bit in self.lookups: 666 726 try: # dictionary lookup 667 current = current[bit s[0]]727 current = current[bit] 668 728 except (TypeError, AttributeError, KeyError): 669 729 try: # attribute lookup 670 current = getattr(current, bit s[0])730 current = getattr(current, bit) 671 731 if callable(current): 672 732 if getattr(current, 'alters_data', False): 673 733 current = settings.TEMPLATE_STRING_IF_INVALID … … 685 745 raise 686 746 except (TypeError, AttributeError): 687 747 try: # list-index lookup 688 current = current[int(bit s[0])]748 current = current[int(bit)] 689 749 except (IndexError, # list index out of range 690 750 ValueError, # invalid literal for int() 691 KeyError, # current is a dict without `int(bit s[0])` key751 KeyError, # current is a dict without `int(bit)` key 692 752 TypeError, # unsubscriptable object 693 753 ): 694 raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit s[0], current)) # missing attribute754 raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute 695 755 except Exception, e: 696 756 if getattr(e, 'silent_variable_failure', False): 697 757 current = settings.TEMPLATE_STRING_IF_INVALID 698 758 else: 699 759 raise 700 del bits[0]701 if isinstance(current, (basestring, Promise)):702 try:703 current = force_unicode(current)704 except UnicodeDecodeError:705 # Failing to convert to unicode can happen sometimes (e.g. debug706 # tracebacks). So we allow it in this particular instance.707 pass708 return current760 761 if isinstance(current, (basestring, Promise)): 762 try: 763 current = force_unicode(current) 764 except UnicodeDecodeError: 765 # Failing to convert to unicode can happen sometimes (e.g. debug 766 # tracebacks). So we allow it in this particular instance. 767 pass 768 return current 709 769 710 770 class Node(object): 711 771 def render(self, context): … … 861 921 862 922 class SimpleNode(Node): 863 923 def __init__(self, vars_to_resolve): 864 self.vars_to_resolve = vars_to_resolve924 self.vars_to_resolve = map(Variable, vars_to_resolve) 865 925 866 926 def render(self, context): 867 resolved_vars = [ resolve_variable(var,context) for var in self.vars_to_resolve]927 resolved_vars = [var.resolve(context) for var in self.vars_to_resolve] 868 928 return func(*resolved_vars) 869 929 870 930 compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode) … … 883 943 884 944 class InclusionNode(Node): 885 945 def __init__(self, vars_to_resolve): 886 self.vars_to_resolve = vars_to_resolve946 self.vars_to_resolve = map(Variable, vars_to_resolve) 887 947 888 948 def render(self, context): 889 resolved_vars = [ resolve_variable(var,context) for var in self.vars_to_resolve]949 resolved_vars = [var.resolve(context) for var in self.vars_to_resolve] 890 950 if takes_context: 891 951 args = [context] + resolved_vars 892 952 else: -
django/template/defaulttags.py
1 1 "Default tags used by the template system, available to all templates." 2 2 3 from django.template import Node, NodeList, Template, Context, resolve_variable3 from django.template import Node, NodeList, Template, Context, Variable 4 4 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END 5 5 from django.template import get_library, Library, InvalidTemplateLibrary 6 6 from django.conf import settings … … 30 30 def render(self, context): 31 31 self.counter += 1 32 32 value = self.cyclevars[self.counter % self.cyclevars_len] 33 value = resolve_variable(value,context)33 value = Variable(value).resolve(context) 34 34 if self.variable_name: 35 35 context[self.variable_name] = value 36 36 return value … … 57 57 58 58 class FirstOfNode(Node): 59 59 def __init__(self, vars): 60 self.vars = vars60 self.vars = map(Variable, vars) 61 61 62 62 def render(self, context): 63 63 for var in self.vars: 64 64 try: 65 value = resolve_variable(var,context)65 value = var.resolve(context) 66 66 except VariableDoesNotExist: 67 67 continue 68 68 if value: … … 147 147 def __init__(self, nodelist, *varlist): 148 148 self.nodelist = nodelist 149 149 self._last_seen = None 150 self._varlist = varlist150 self._varlist = map(Variable, varlist) 151 151 152 152 def render(self, context): 153 153 if 'forloop' in context and context['forloop']['first']: … … 156 156 if self._varlist: 157 157 # Consider multiple parameters. 158 158 # This automatically behaves like a OR evaluation of the multiple variables. 159 compare_to = [ resolve_variable(var,context) for var in self._varlist]159 compare_to = [var.resolve(context) for var in self._varlist] 160 160 else: 161 161 compare_to = self.nodelist.render(context) 162 162 except VariableDoesNotExist: … … 175 175 176 176 class IfEqualNode(Node): 177 177 def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): 178 self.var1, self.var2 = var1, var2178 self.var1, self.var2 = Variable(var1), Variable(var2) 179 179 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false 180 180 self.negate = negate 181 181 … … 184 184 185 185 def render(self, context): 186 186 try: 187 val1 = resolve_variable(self.var1,context)187 val1 = self.var1.resolve(context) 188 188 except VariableDoesNotExist: 189 189 val1 = None 190 190 try: 191 val2 = resolve_variable(self.var2,context)191 val2 = self.var2.resolve(context) 192 192 except VariableDoesNotExist: 193 193 val2 = None 194 194 if (self.negate and val1 != val2) or (not self.negate and val1 == val2): -
django/template/loader_tags.py
1 from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable1 from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable 2 2 from django.template import Library, Node 3 3 from django.template.loader import get_template, get_template_from_string, find_template_source 4 4 from django.conf import settings … … 99 99 100 100 class IncludeNode(Node): 101 101 def __init__(self, template_name): 102 self.template_name = template_name102 self.template_name = Variable(template_name) 103 103 104 104 def render(self, context): 105 105 try: 106 template_name = resolve_variable(self.template_name,context)106 template_name = self.template_name.resolve(context) 107 107 t = get_template(template_name) 108 108 return t.render(context) 109 109 except TemplateSyntaxError, e: -
docs/templates_python.txt
928 928 ``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then 929 929 format it accordingly. 930 930 931 .. note:: 932 The ``resolve_variable()`` function will throw a ``VariableDoesNotExist`` 933 exception if it cannot resolve the string passed to it in the current 934 context of the page. 931 .. admonition:: New in development version: 935 932 933 Variable resolution has changed in the development version of Django. 934 ``template.resolve_variable()`` is still available, but has been deprecated 935 in favor of a new ``template.Variable`` class. Using this class will usually 936 be more efficient than calling ``template.resolve_variable`` 937 938 To use the ``Variable`` class, simply instantiate it with the name of the 939 variable to be resolved, and then call ``variable.resolve(context)``. So, 940 in the development version, the above example would be more correctly 941 written as: 942 943 .. parsed-literal:: 944 945 class FormatTimeNode(template.Node): 946 def __init__(self, date_to_be_formatted, format_string): 947 self.date_to_be_formatted = **Variable(date_to_be_formatted)** 948 self.format_string = format_string 949 950 def render(self, context): 951 try: 952 actual_date = **self.date_to_be_formatted.resolve(context)** 953 return actual_date.strftime(self.format_string) 954 except template.VariableDoesNotExist: 955 return '' 956 957 Changes are highlighted in bold. 958 959 Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot 960 resolve the string passed to it in the current context of the page. 961 936 962 Shortcut for simple tags 937 963 ~~~~~~~~~~~~~~~~~~~~~~~~ 938 964