web/lib/django/template/context.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     1 from django.core.exceptions import ImproperlyConfigured
     1 from django.core.exceptions import ImproperlyConfigured
     2 from django.utils.importlib import import_module
     2 from django.utils.importlib import import_module
     3 
     3 
       
     4 # Cache of actual callables.
     4 _standard_context_processors = None
     5 _standard_context_processors = None
       
     6 # We need the CSRF processor no matter what the user has in their settings,
       
     7 # because otherwise it is a security vulnerability, and we can't afford to leave
       
     8 # this to human error or failure to read migration instructions.
       
     9 _builtin_context_processors =  ('django.core.context_processors.csrf',)
     5 
    10 
     6 class ContextPopException(Exception):
    11 class ContextPopException(Exception):
     7     "pop() has been called more times than push()"
    12     "pop() has been called more times than push()"
     8     pass
    13     pass
     9 
    14 
    10 class Context(object):
    15 class BaseContext(object):
    11     "A stack container for variable context"
    16     def __init__(self, dict_=None):
    12     def __init__(self, dict_=None, autoescape=True, current_app=None):
       
    13         dict_ = dict_ or {}
    17         dict_ = dict_ or {}
    14         self.dicts = [dict_]
    18         self.dicts = [dict_]
    15         self.autoescape = autoescape
       
    16         self.current_app = current_app
       
    17 
    19 
    18     def __repr__(self):
    20     def __repr__(self):
    19         return repr(self.dicts)
    21         return repr(self.dicts)
    20 
    22 
    21     def __iter__(self):
    23     def __iter__(self):
    22         for d in self.dicts:
    24         for d in reversed(self.dicts):
    23             yield d
    25             yield d
    24 
    26 
    25     def push(self):
    27     def push(self):
    26         d = {}
    28         d = {}
    27         self.dicts = [d] + self.dicts
    29         self.dicts.append(d)
    28         return d
    30         return d
    29 
    31 
    30     def pop(self):
    32     def pop(self):
    31         if len(self.dicts) == 1:
    33         if len(self.dicts) == 1:
    32             raise ContextPopException
    34             raise ContextPopException
    33         return self.dicts.pop(0)
    35         return self.dicts.pop()
    34 
    36 
    35     def __setitem__(self, key, value):
    37     def __setitem__(self, key, value):
    36         "Set a variable in the current context"
    38         "Set a variable in the current context"
    37         self.dicts[0][key] = value
    39         self.dicts[-1][key] = value
    38 
    40 
    39     def __getitem__(self, key):
    41     def __getitem__(self, key):
    40         "Get a variable's value, starting at the current context and going upward"
    42         "Get a variable's value, starting at the current context and going upward"
    41         for d in self.dicts:
    43         for d in reversed(self.dicts):
    42             if key in d:
    44             if key in d:
    43                 return d[key]
    45                 return d[key]
    44         raise KeyError(key)
    46         raise KeyError(key)
    45 
    47 
    46     def __delitem__(self, key):
    48     def __delitem__(self, key):
    47         "Delete a variable from the current context"
    49         "Delete a variable from the current context"
    48         del self.dicts[0][key]
    50         del self.dicts[-1][key]
    49 
    51 
    50     def has_key(self, key):
    52     def has_key(self, key):
    51         for d in self.dicts:
    53         for d in self.dicts:
    52             if key in d:
    54             if key in d:
    53                 return True
    55                 return True
    54         return False
    56         return False
    55 
    57 
    56     __contains__ = has_key
    58     def __contains__(self, key):
       
    59         return self.has_key(key)
    57 
    60 
    58     def get(self, key, otherwise=None):
    61     def get(self, key, otherwise=None):
    59         for d in self.dicts:
    62         for d in reversed(self.dicts):
    60             if key in d:
    63             if key in d:
    61                 return d[key]
    64                 return d[key]
    62         return otherwise
    65         return otherwise
       
    66 
       
    67 class Context(BaseContext):
       
    68     "A stack container for variable context"
       
    69     def __init__(self, dict_=None, autoescape=True, current_app=None):
       
    70         self.autoescape = autoescape
       
    71         self.current_app = current_app
       
    72         self.render_context = RenderContext()
       
    73         super(Context, self).__init__(dict_)
    63 
    74 
    64     def update(self, other_dict):
    75     def update(self, other_dict):
    65         "Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
    76         "Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
    66         if not hasattr(other_dict, '__getitem__'):
    77         if not hasattr(other_dict, '__getitem__'):
    67             raise TypeError('other_dict must be a mapping (dictionary-like) object.')
    78             raise TypeError('other_dict must be a mapping (dictionary-like) object.')
    68         self.dicts = [other_dict] + self.dicts
    79         self.dicts.append(other_dict)
    69         return other_dict
    80         return other_dict
       
    81 
       
    82 class RenderContext(BaseContext):
       
    83     """
       
    84     A stack container for storing Template state.
       
    85 
       
    86     RenderContext simplifies the implementation of template Nodes by providing a
       
    87     safe place to store state between invocations of a node's `render` method.
       
    88 
       
    89     The RenderContext also provides scoping rules that are more sensible for
       
    90     'template local' variables. The render context stack is pushed before each
       
    91     template is rendered, creating a fresh scope with nothing in it. Name
       
    92     resolution fails if a variable is not found at the top of the RequestContext
       
    93     stack. Thus, variables are local to a specific template and don't affect the
       
    94     rendering of other templates as they would if they were stored in the normal
       
    95     template context.
       
    96     """
       
    97     def __iter__(self):
       
    98         for d in self.dicts[-1]:
       
    99             yield d
       
   100 
       
   101     def has_key(self, key):
       
   102         return key in self.dicts[-1]
       
   103 
       
   104     def get(self, key, otherwise=None):
       
   105         d = self.dicts[-1]
       
   106         if key in d:
       
   107             return d[key]
       
   108         return otherwise
    70 
   109 
    71 # This is a function rather than module-level procedural code because we only
   110 # This is a function rather than module-level procedural code because we only
    72 # want it to execute if somebody uses RequestContext.
   111 # want it to execute if somebody uses RequestContext.
    73 def get_standard_processors():
   112 def get_standard_processors():
    74     from django.conf import settings
   113     from django.conf import settings
    75     global _standard_context_processors
   114     global _standard_context_processors
    76     if _standard_context_processors is None:
   115     if _standard_context_processors is None:
    77         processors = []
   116         processors = []
    78         for path in settings.TEMPLATE_CONTEXT_PROCESSORS:
   117         collect = []
       
   118         collect.extend(_builtin_context_processors)
       
   119         collect.extend(settings.TEMPLATE_CONTEXT_PROCESSORS)
       
   120         for path in collect:
    79             i = path.rfind('.')
   121             i = path.rfind('.')
    80             module, attr = path[:i], path[i+1:]
   122             module, attr = path[:i], path[i+1:]
    81             try:
   123             try:
    82                 mod = import_module(module)
   124                 mod = import_module(module)
    83             except ImportError, e:
   125             except ImportError, e: