1 # -*- coding: utf-8 -*-
2 # This file is part of django-ssify, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See README.md for more information.
6 Defines decorators for use in ssify-enabled projects.
8 from __future__ import unicode_literals
10 from inspect import getargspec
12 from django.conf import settings
13 from django.http import Http404
14 from django.template.base import parse_bits
15 from django.utils.translation import get_language, activate
16 from .cache import cache_include, DEFAULT_TIMEOUT
17 from . import exceptions
18 from .variables import SsiVariable
21 def ssi_included(view=None, use_lang=True,
22 timeout=DEFAULT_TIMEOUT, version=None,
23 get_ssi_vars=None, patch_response=None):
25 Marks a view to be used as a snippet to be included with SSI.
27 If use_lang is True (which is default), the URL pattern for such
28 a view must provide a keyword argument named 'lang' for language.
29 SSI included views don't use language or content negotiation, so
30 everything they need to know has to be included in the URL.
32 get_ssi_vars should be a callable which takes the view's arguments
33 and returns the names of SSI variables it uses.
37 @functools.wraps(view)
38 def new_view(request, *args, **kwargs):
41 lang = kwargs.pop('lang')
43 raise exceptions.NoLangFieldError(request)
44 if lang not in [language[0] for language in settings.LANGUAGES]:
46 current_lang = get_language()
48 request.LANGUAGE_CODE = lang
49 response = view(request, *args, **kwargs)
51 activate(current_lang)
52 if response.status_code == 200:
53 # We don't want this view to be cached in
54 # UpdateCacheMiddleware. We'll just cache the contents
55 # ourselves, and point the webserver to use this cache.
56 request._cache_update_cache = False
58 def _check_included_vars(response):
59 used_vars = request.ssi_vars_needed
61 # Remove the ssi vars that should be provided
62 # by the including view.
63 pass_vars = get_ssi_vars(*args, **kwargs)
66 if not isinstance(var, SsiVariable):
67 var = SsiVariable(*var)
69 del used_vars[var.name]
72 exceptions.UnusedSsiVarsWarning(
75 raise exceptions.UndeclaredSsiVarsError(
77 request.ssi_vars_needed = {}
79 # Don't use default django response caching for this view,
80 # just save the contents instead.
81 cache_include(request.path, response.content,
82 timeout=timeout, version=version)
84 if hasattr(response, 'render') and callable(response.render):
85 response.add_post_render_callback(_check_included_vars)
87 _check_included_vars(response)
91 # Remember get_ssi_vars so that in can be computed from args/kwargs
93 new_view.get_ssi_vars = get_ssi_vars
94 new_view.ssi_patch_response = patch_response
96 return dec(view) if view else dec
99 def ssi_variable(register, name=None, patch_response=None):
101 Creates a template tag representing an SSI variable from a function.
103 The function must take 'request' as its first argument.
104 It may take other arguments, which should be provided when using
112 function_name = (name or
113 getattr(func, '_decorated_function', func).__name__)
114 lib_name = func.__module__.rsplit('.', 1)[-1]
115 tagpath = "%s.%s" % (lib_name, function_name)
116 # Make sure the function takes request parameter.
117 params, varargs, varkw, defaults = getargspec(func)
118 assert params and params[0] == 'request', '%s is decorated with '\
119 'request_info_tag, so it must take `request` for '\
120 'its first argument.' % (tagpath)
122 @register.tag(name=function_name)
123 def _ssi_var_tag(parser, token):
125 Creates a SSI variable reference for a request-dependent info.
130 {% ri_tag args... as variable %}
133 {% ssi_include 'some-snippet' variable %}
139 bits = token.split_contents()[1:]
141 # Is it the 'as' form?
142 if len(bits) >= 2 and bits[-2] == 'as':
148 # Parse the arguments like Django's generic tags do.
149 args, kwargs = parse_bits(parser, bits,
150 ['context'] + params[1:], varargs, varkw,
151 defaults, takes_context=True,
153 return SsiVariableNode(tagpath, args, kwargs, patch_response, asvar)
154 _ssi_var_tag.get_value = func
161 from .variables import SsiVariableNode