=== modified file '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_var |
| 75 | 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_var |
| 159 | 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 |
=== modified file 'django/contrib/comments/templatetags/comments.py'
|
|
|
18 | 18 | ratings_optional=False, ratings_required=False, rating_options='', |
19 | 19 | is_public=True): |
20 | 20 | self.content_type = content_type |
| 21 | if obj_id_lookup is not None: |
| 22 | obj_id_lookup = template.Variable |
21 | 23 | self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free |
22 | 24 | self.photos_optional, self.photos_required = photos_optional, photos_required |
23 | 25 | self.ratings_optional, self.ratings_required = ratings_optional, ratings_required |
… |
… |
|
31 | 33 | context.push() |
32 | 34 | if self.obj_id_lookup_var is not None: |
33 | 35 | try: |
34 | | self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context) |
| 36 | self.obj_id = self.obj_id_lookup_var.resolve(context) |
35 | 37 | except template.VariableDoesNotExist: |
36 | 38 | return '' |
37 | 39 | # Validate that this object ID is valid for this content-type. |
… |
… |
|
74 | 76 | class CommentCountNode(template.Node): |
75 | 77 | def __init__(self, package, module, context_var_name, obj_id, var_name, free): |
76 | 78 | self.package, self.module = package, module |
| 79 | if context_var_name is not None: |
| 80 | context_var_name = template.Variable(context_var_name) |
77 | 81 | self.context_var_name, self.obj_id = context_var_name, obj_id |
78 | 82 | self.var_name, self.free = var_name, free |
79 | 83 | |
… |
… |
|
81 | 85 | from django.conf import settings |
82 | 86 | manager = self.free and FreeComment.objects or Comment.objects |
83 | 87 | if self.context_var_name is not None: |
84 | | self.obj_id = template.resolve_variable(self.context_var_name, context) |
| 88 | self.obj_id = self.context_var_name.resolve(context) |
85 | 89 | comment_count = manager.filter(object_id__exact=self.obj_id, |
86 | 90 | content_type__app_label__exact=self.package, |
87 | 91 | content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() |
… |
… |
|
91 | 95 | class CommentListNode(template.Node): |
92 | 96 | def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): |
93 | 97 | self.package, self.module = package, module |
| 98 | if context_var_name is not None: |
| 99 | context_var_name = template.Variable(context_var_name) |
94 | 100 | self.context_var_name, self.obj_id = context_var_name, obj_id |
95 | 101 | self.var_name, self.free = var_name, free |
96 | 102 | self.ordering = ordering |
… |
… |
|
101 | 107 | get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma |
102 | 108 | if self.context_var_name is not None: |
103 | 109 | try: |
104 | | self.obj_id = template.resolve_variable(self.context_var_name, context) |
| 110 | self.obj_id = self.context_var_name.resolve(context) |
105 | 111 | except template.VariableDoesNotExist: |
106 | 112 | return '' |
107 | 113 | kwargs = { |
=== modified file 'django/template/__init__.py'
|
|
|
93 | 93 | tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), |
94 | 94 | re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), |
95 | 95 | re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) |
96 | | # matches if the string is valid number |
97 | | number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$') |
98 | 96 | |
99 | 97 | # global dictionary of libraries that have been loaded using get_library |
100 | 98 | libraries = {} |
… |
… |
|
568 | 566 | elif constant_arg is not None: |
569 | 567 | args.append((False, constant_arg.replace(r'\"', '"'))) |
570 | 568 | elif var_arg: |
571 | | args.append((True, var_arg)) |
| 569 | args.append((True, Variable(var_arg))) |
572 | 570 | filter_func = parser.find_filter(filter_name) |
573 | 571 | self.args_check(filter_name,filter_func, args) |
574 | 572 | filters.append( (filter_func,args)) |
575 | 573 | upto = match.end() |
576 | 574 | if upto != len(token): |
577 | 575 | raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token) |
578 | | self.var, self.filters = var, filters |
| 576 | self.filters = filters |
| 577 | self.var = Variable(var) |
579 | 578 | |
580 | 579 | def resolve(self, context, ignore_failures=False): |
581 | 580 | try: |
582 | | obj = resolve_variable(self.var, context) |
| 581 | obj = self.var.resolve(context) |
583 | 582 | except VariableDoesNotExist: |
584 | 583 | if ignore_failures: |
585 | 584 | obj = None |
… |
… |
|
599 | 598 | if not lookup: |
600 | 599 | arg_vals.append(arg) |
601 | 600 | else: |
602 | | arg_vals.append(resolve_variable(arg, context)) |
| 601 | arg_vals.append(arg.resolve(context)) |
603 | 602 | obj = func(obj, *arg_vals) |
604 | 603 | return obj |
605 | 604 | |
… |
… |
|
658 | 657 | |
659 | 658 | (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') |
660 | 659 | """ |
661 | | if number_re.match(path): |
662 | | number_type = '.' in path and float or int |
663 | | current = number_type(path) |
664 | | elif path[0] in ('"', "'") and path[0] == path[-1]: |
665 | | current = path[1:-1] |
666 | | else: |
| 660 | return Variable(path).resolve(context) |
| 661 | |
| 662 | class LiteralVariable(object): |
| 663 | |
| 664 | def __init__(self, val): |
| 665 | self.val = val |
| 666 | |
| 667 | def resolve(self, context): |
| 668 | return self.val |
| 669 | |
| 670 | def __str__(self): |
| 671 | return self.val |
| 672 | |
| 673 | def Variable(val): |
| 674 | try: |
| 675 | # note we're not catching OverflowError here; point of debate on how best to handle that... |
| 676 | current = float(val) |
| 677 | if '.' not in val: |
| 678 | # downside to this approach is that 1e07 becomes an int; float may be preferable still. |
| 679 | current = int(current) |
| 680 | elif val[-1] == '.': |
| 681 | # 2. is invalid |
| 682 | raise ValueError |
| 683 | return LiteralVariable(current) |
| 684 | except ValueError: |
| 685 | pass |
| 686 | if val[0] in "\"'" and val[0] == val[-1]: |
| 687 | return LiteralVariable(val[1:-1]) |
| 688 | return ChainedLookupVariable(val) |
| 689 | |
| 690 | class ChainedLookupVariable(object): |
| 691 | |
| 692 | def __init__(self, val): |
| 693 | self.lookups = tuple(val.split(VARIABLE_ATTRIBUTE_SEPARATOR)) |
| 694 | |
| 695 | def resolve(self, context): |
667 | 696 | current = context |
668 | | bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) |
669 | | while bits: |
| 697 | for bit in self.lookups: |
670 | 698 | try: # dictionary lookup |
671 | | current = current[bits[0]] |
| 699 | current = current[bit] |
672 | 700 | except (TypeError, AttributeError, KeyError): |
673 | 701 | try: # attribute lookup |
674 | | current = getattr(current, bits[0]) |
| 702 | current = getattr(current, bit) |
675 | 703 | if callable(current): |
676 | 704 | if getattr(current, 'alters_data', False): |
677 | 705 | current = settings.TEMPLATE_STRING_IF_INVALID |
… |
… |
|
689 | 717 | raise |
690 | 718 | except (TypeError, AttributeError): |
691 | 719 | try: # list-index lookup |
692 | | current = current[int(bits[0])] |
| 720 | current = current[int(bit)] |
693 | 721 | except (IndexError, # list index out of range |
694 | 722 | ValueError, # invalid literal for int() |
695 | | KeyError, # current is a dict without `int(bits[0])` key |
| 723 | KeyError, # current is a dict without `int(bit)` key |
696 | 724 | TypeError, # unsubscriptable object |
697 | 725 | ): |
698 | | raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute |
| 726 | raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute |
699 | 727 | except Exception, e: |
700 | 728 | if getattr(e, 'silent_variable_failure', False): |
701 | 729 | current = settings.TEMPLATE_STRING_IF_INVALID |
702 | 730 | else: |
703 | 731 | raise |
704 | | del bits[0] |
705 | | if isinstance(current, (basestring, Promise)): |
706 | | try: |
707 | | current = force_unicode(current) |
708 | | except UnicodeDecodeError: |
709 | | # Failing to convert to unicode can happen sometimes (e.g. debug |
710 | | # tracebacks). So we allow it in this particular instance. |
711 | | pass |
712 | | return current |
| 732 | |
| 733 | if isinstance(current, (basestring, Promise)): |
| 734 | try: |
| 735 | current = force_unicode(current) |
| 736 | except UnicodeDecodeError: |
| 737 | # Failing to convert to unicode can happen sometimes (e.g. debug |
| 738 | # tracebacks). So we allow it in this particular instance. |
| 739 | pass |
| 740 | return current |
| 741 | |
| 742 | def __str__(self): |
| 743 | return VARIABLE_ATTRIBUTE_SEPARATOR.join(self.lookups) |
713 | 744 | |
714 | 745 | class Node(object): |
715 | 746 | def render(self, context): |
… |
… |
|
865 | 896 | |
866 | 897 | class SimpleNode(Node): |
867 | 898 | def __init__(self, vars_to_resolve): |
868 | | self.vars_to_resolve = vars_to_resolve |
| 899 | self.vars_to_resolve = map(Variable, vars_to_resolve) |
869 | 900 | |
870 | 901 | def render(self, context): |
871 | | resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] |
872 | | return func(*resolved_vars) |
| 902 | return func(*[var.resolve(context) for var in self.vars_to_resolve]) |
873 | 903 | |
874 | 904 | compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode) |
875 | 905 | compile_func.__doc__ = func.__doc__ |
… |
… |
|
887 | 917 | |
888 | 918 | class InclusionNode(Node): |
889 | 919 | def __init__(self, vars_to_resolve): |
890 | | self.vars_to_resolve = vars_to_resolve |
| 920 | self.vars_to_resolve = map(Variable, vars_to_resolve) |
891 | 921 | |
892 | 922 | def render(self, context): |
893 | | resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve] |
| 923 | resolved_vars = [var.resolve(context) for var in self.vars_to_resolve] |
894 | 924 | if takes_context: |
895 | 925 | args = [context] + resolved_vars |
896 | 926 | else: |
=== modified file 'django/template/defaultfilters.py'
|
|
|
1 | 1 | "Default variable filters" |
2 | 2 | |
3 | | from django.template import resolve_variable, Library |
| 3 | 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 |
… |
… |
|
290 | 290 | Takes a list of dicts, returns that list sorted by the property given in |
291 | 291 | the argument. |
292 | 292 | """ |
293 | | decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] |
| 293 | var_resolve = Variable(arg).resolve |
| 294 | decorated = [(var_resolve(item), item) for item in value] |
294 | 295 | decorated.sort() |
295 | 296 | return [item[1] for item in decorated] |
296 | 297 | |
… |
… |
|
299 | 300 | Takes a list of dicts, returns that list sorted in reverse order by the |
300 | 301 | property given in the argument. |
301 | 302 | """ |
302 | | decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value] |
| 303 | var_resolve = Variable(arg).resolve |
| 304 | decorated = [(var_resolve(item), item) for item in value] |
303 | 305 | decorated.sort() |
304 | 306 | decorated.reverse() |
305 | 307 | return [item[1] for item in decorated] |
=== modified file '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_variable |
| 3 | 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 |
… |
… |
|
56 | 56 | |
57 | 57 | class FirstOfNode(Node): |
58 | 58 | def __init__(self, vars): |
59 | | self.vars = vars |
| 59 | self.vars = map(Variable, vars) |
60 | 60 | |
61 | 61 | def render(self, context): |
62 | 62 | for var in self.vars: |
63 | 63 | try: |
64 | | value = resolve_variable(var, context) |
| 64 | value = var.resolve(context) |
65 | 65 | except VariableDoesNotExist: |
66 | 66 | continue |
67 | 67 | if value: |
… |
… |
|
146 | 146 | def __init__(self, nodelist, *varlist): |
147 | 147 | self.nodelist = nodelist |
148 | 148 | self._last_seen = None |
149 | | self._varlist = varlist |
| 149 | self._varlist = map(Variable, varlist) |
150 | 150 | |
151 | 151 | def render(self, context): |
152 | 152 | if 'forloop' in context and context['forloop']['first']: |
… |
… |
|
155 | 155 | if self._varlist: |
156 | 156 | # Consider multiple parameters. |
157 | 157 | # This automatically behaves like a OR evaluation of the multiple variables. |
158 | | compare_to = [resolve_variable(var, context) for var in self._varlist] |
| 158 | compare_to = [var.resolve(context) for var in self._varlist] |
159 | 159 | else: |
160 | 160 | compare_to = self.nodelist.render(context) |
161 | 161 | except VariableDoesNotExist: |
… |
… |
|
174 | 174 | |
175 | 175 | class IfEqualNode(Node): |
176 | 176 | def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): |
177 | | self.var1, self.var2 = var1, var2 |
| 177 | self.var1, self.var2 = Variable(var1), Variable(var2) |
178 | 178 | self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false |
179 | 179 | self.negate = negate |
180 | 180 | |
… |
… |
|
183 | 183 | |
184 | 184 | def render(self, context): |
185 | 185 | try: |
186 | | val1 = resolve_variable(self.var1, context) |
| 186 | val1 = self.var1.resolve(context) |
187 | 187 | except VariableDoesNotExist: |
188 | 188 | val1 = None |
189 | 189 | try: |
190 | | val2 = resolve_variable(self.var2, context) |
| 190 | val2 = self.var2.resolve(context) |
191 | 191 | except VariableDoesNotExist: |
192 | 192 | val2 = None |
193 | 193 | if (self.negate and val1 != val2) or (not self.negate and val1 == val2): |
=== modified file 'django/template/loader_tags.py'
|
|
|
1 | | from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable |
| 1 | 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_name |
| 102 | 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: |
=== modified file 'django/templatetags/i18n.py'
|
|
|
1 | | from django.template import Node, resolve_variable |
| 1 | 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 = value |
| 35 | 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: |
=== modified file 'docs/templates_python.txt'
|
|
|
864 | 864 | |
865 | 865 | You also have to change the renderer to retrieve the actual contents of the |
866 | 866 | ``date_updated`` property of the ``blog_entry`` object. This can be |
867 | | accomplished by using the ``resolve_variable()`` function in |
868 | | ``django.template``. You pass ``resolve_variable()`` the variable name and the |
869 | | current context, available in the ``render`` method:: |
| 867 | accomplished by using the ``Variable`` class in ``django.template``. |
| 868 | You pass ``Variable`` the variable name, and invoke the ``resolve`` method with the |
| 869 | current context:: |
870 | 870 | |
871 | 871 | from django import template |
872 | | from django.template import resolve_variable |
| 872 | from django.template import Variable |
873 | 873 | import datetime |
874 | 874 | class FormatTimeNode(template.Node): |
875 | 875 | def __init__(self, date_to_be_formatted, format_string): |
876 | | self.date_to_be_formatted = date_to_be_formatted |
| 876 | self.date_to_be_formatted = Variable(date_to_be_formatted) |
877 | 877 | self.format_string = format_string |
878 | 878 | |
879 | 879 | def render(self, context): |
880 | 880 | try: |
881 | | actual_date = resolve_variable(self.date_to_be_formatted, context) |
| 881 | actual_date = self.date_to_be_formatted.resolve(context) |
882 | 882 | return actual_date.strftime(self.format_string) |
883 | 883 | except template.VariableDoesNotExist: |
884 | 884 | return '' |
885 | 885 | |
886 | | ``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then |
887 | | format it accordingly. |
| 886 | ``render`` will try to resolve ``blog_entry.date_updated`` via ``Variable.resolve``, |
| 887 | and then format it accordingly. |
888 | 888 | |
889 | 889 | .. note:: |
890 | | The ``resolve_variable()`` function will throw a ``VariableDoesNotExist`` |
| 890 | The ``Variable.resolve`` method will throw a ``VariableDoesNotExist`` |
891 | 891 | exception if it cannot resolve the string passed to it in the current |
892 | 892 | context of the page. |
| 893 | |
| 894 | Additionally, ``resolve_variable(arg, context)`` is a function invoking |
| 895 | ``Variable(arg).resolve(context)``. The ``Variable`` should be used instead, |
| 896 | since ``resolve_variable`` is deprecated. |
893 | 897 | |
894 | 898 | Shortcut for simple tags |
895 | 899 | ~~~~~~~~~~~~~~~~~~~~~~~~ |