PageRenderTime 32ms CodeModel.GetById 24ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/view_shortcuts/decorators.py

https://bitbucket.org/neithere/django-view-shortcuts/
Python | 107 lines | 80 code | 12 blank | 15 comment | 8 complexity | 380b779ba9eedcd0041666001a562d98 MD5 | raw file
  1# -*- coding: utf-8 -*-
  2#
  3#  Copyright (c) 2008 Alexander Solovyov (parts)
  4#  Copyright (c) 2008--2009 Andy Mikhailenko and contributors
  5#
  6#  This file is part of Django View Shortcuts.
  7#
  8#  Django View Shortcuts is free software under terms of the GNU Lesser
  9#  General Public License version 3 (LGPLv3) as published by the Free
 10#  Software Foundation. See the file README for copying conditions.
 11#
 12
 13from django.http import HttpRequest
 14from django.template import RequestContext
 15from django.shortcuts import render_to_response
 16
 17def render_to(template=None):
 18    """
 19    Decorator for Django views that sends returned dict to render_to_response
 20    function with given template and RequestContext as context instance.
 21
 22    If view doesn't return dict then decorator simply returns output.
 23    Additionally view can return two-tuple, which must contain dict as first
 24    element and string with template name as second. This string will
 25    override template name, given as parameter
 26
 27    Parameters:
 28
 29    :param template: template name to use
 30
 31    Usage::
 32
 33        >>> @render_to('foo.html')
 34        ... def view_foo(request):
 35        ...     return {'foo': 'bar'}
 36        ...
 37
 38    Template name can be omitted. The following code will render the output
 39    to template "foo_detail.html" -- its name is equal to the view function name::
 40
 41        >>> @render_to()
 42        ... def foo_detail(request, pk):
 43        ...     obj = Foo.objects.get(pk=pk)
 44        ...     return {'object': obj}
 45
 46    Class views are supported too::
 47
 48        >>> @render_to()
 49        ... class ViewFoo(object):
 50        ...     def __init__(self, foo):
 51        ...         self.foo = foo
 52        ...     def __call__(self, request, *args, **kwargs):
 53        ...         qs = Foo.objects.filter(foo=self.foo)
 54        ...         return {'object_list': qs}
 55
 56    Source: <http://piranha.org.ua/blog/2008/03/22/render-to-improved/>
 57
 58    Improved by Andy Mikhailenko, 2008--2009:
 59    + added support for class views (i.e. with "self" in args);
 60    + template name can be omitted if it's equal to function name + 'html' extension.
 61    """
 62    def renderer(func):
 63        def wrapper(*args, **kw):
 64            # ensure HttpRequest instance is passed properly
 65            request = None
 66            for arg in args:
 67                if isinstance(arg, HttpRequest):
 68                    request = arg
 69                    break
 70            if not request:
 71                raise ValueError, 'Request not found in arguments'
 72
 73            # call the view function
 74            output = func(*args, **kw)
 75
 76            # process results
 77            if isinstance(output, (list, tuple)):
 78                return render_to_response(output[1], output[0], RequestContext(request))
 79            elif isinstance(output, dict):
 80                # if template not specified, use view function name instead
 81                if template:
 82                    tmpl = template
 83                else:
 84                    if func.__name__ == '<lambda>':
 85                        raise TypeError, 'Decorator render_to cannot be used ' \
 86                                         'with anonymous functions if template '\
 87                                         'name is not provided.'
 88                    tmpl = '%s.html' % func.__name__
 89                return render_to_response(tmpl, output, RequestContext(request))
 90            return output
 91        # preserve custom attributes of the view function
 92        wrapper.__dict__ = dict(func.__dict__)
 93        return wrapper
 94    return renderer
 95
 96def cached_property(f):
 97    """A property which value is computed only once and then stored with
 98    the instance for quick repeated retrieval.
 99    """
100    def _closure(self):
101        cache_key = '_cache__%s' % f.__name__
102        value = getattr(self, cache_key, None)
103        if value == None:
104            value = f(self)
105            setattr(self, cache_key, value)
106        return value
107    return property(_closure)