2 from inspect import getargspec
4 from django.template.base import parse_bits
5 from django.utils.translation import get_language, activate
6 from .store import cache_include
7 from . import exceptions
8 from .variables import SsiVariable
11 def ssi_included(view=None, use_lang=True, get_ssi_vars=None):
13 Marks a view to be used as a snippet to be included with SSI.
15 If use_lang is True (which is default), the URL pattern for such
16 a view must provide a keyword argument named 'lang' for language.
17 SSI included views don't use language or content negotiation, so
18 everything they need to know has to be included in the URL.
20 get_ssi_vars should be a callable which takes the view's arguments
21 and returns the names of SSI variables it uses.
25 @functools.wraps(view)
26 def new_view(request, *args, **kwargs):
29 lang = kwargs.pop('lang')
31 raise exceptions.NoLangFieldError(request)
32 current_lang = get_language()
34 response = view(request, *args, **kwargs)
36 activate(current_lang)
37 if response.status_code == 200:
38 request._cache_update_cache = False
40 def _check_included_vars(response):
41 used_vars = request.ssi_vars_needed
43 # Remove the ssi vars that should be provided
44 # by the including view.
45 pass_vars = set(get_ssi_vars(*args, **kwargs))
48 if not isinstance(var, SsiVariable):
49 var = SsiVariable(*var)
51 del used_vars[var.name]
54 exceptions.UnusedSsiVarsWarning(
57 raise exceptions.UndeclaredSsiVarsError(
59 request.ssi_vars_needed = {}
61 # Don't use default django response caching for this view,
62 # just save the contents instead.
63 cache_include(request.path, response.content)
65 if hasattr(response, 'render') and callable(response.render):
66 response.add_post_render_callback(_check_included_vars)
68 _check_included_vars(response)
72 # Remember get_ssi_vars so that in can be computed from args/kwargs
74 new_view.get_ssi_vars = get_ssi_vars
76 return dec(view) if view else dec
79 def ssi_variable(register, vary=None, name=None):
83 function_name = (name or
84 getattr(func, '_decorated_function', func).__name__)
85 lib_name = func.__module__.rsplit('.', 1)[-1]
86 tagpath = "%s.%s" % (lib_name, function_name)
87 # Make sure the function takes request parameter.
88 params, varargs, varkw, defaults = getargspec(func)
89 assert params and params[0] == 'request', '%s is decorated with '\
90 'request_info_tag, so it must take `request` for '\
91 'its first argument.' % (tagpath)
93 @register.tag(name=function_name)
94 def _ssi_var_tag(parser, token):
96 Creates a SSI variable reference for a request-dependent info.
101 {% ri_tag args... as variable %}
104 {% ssi_include 'some-snippet' variable %}
110 bits = token.split_contents()[1:]
112 # Is it the 'as' form?
113 if len(bits) >= 2 and bits[-2] == 'as':
119 # Parse the arguments like Django's generic tags do.
120 args, kwargs = parse_bits(parser, bits,
121 ['context'] + params[1:], varargs, varkw,
122 defaults, takes_context=True,
124 return SsiVariableNode(tagpath, args, kwargs, vary, asvar)
125 _ssi_var_tag.get_value = func
132 from .variables import SsiVariableNode