Source code for django_utils.view_decorators

import six
import json
from django.template import loader as django_loader
from django import http
from django.template import RequestContext
from django.contrib.auth import decorators
from django.conf import settings
from django.core import serializers
from django.db import models
from django.core import urlresolvers

    from coffin import shortcuts as coffin_shortcuts
except ImportError:
    coffin_shortcuts = None

[docs]class ViewError(Exception): pass
[docs]class UnknownViewResponseError(ViewError): pass
[docs]def json_default_handler(obj): if hasattr(obj, 'isoformat'): return obj.isoformat() else: raise TypeError('Object of type %s with value of %s is not JSON ' 'serializable' % (type(obj), repr(obj)))
[docs]def redirect(url='./', *args, **kwargs): if '/' not in url or args or kwargs: url = urlresolvers.reverse(url, args=args, kwargs=kwargs) return http.HttpResponseRedirect(url)
[docs]def permanent_redirect(url, *args, **kwargs): if '/' not in url or args or kwargs: url = urlresolvers.reverse(url, args=args, kwargs=kwargs) return http.HttpResponsePermanentRedirect(url)
REQUEST_PROPERTIES = { 'redirect': redirect, 'permanent_redirect': permanent_redirect, 'not_found': http.HttpResponseNotFound, 'reverse': urlresolvers.reverse, } def _prepare_request(request, app, view): '''Add context and extra methods to the request''' request.context = RequestContext(request) request.context['view'] = view request.context['app'] = app request.context['request'] = request for k, v in REQUEST_PROPERTIES.items(): setattr(request, k, v) return request def _process_response(request, response, response_class): '''Generic response processing function, always returns HttpResponse''' '''If we add something to the context stack, pop it after adding''' pop = False try: if isinstance(response, (dict, list, models.query.QuerySet)): if request.ajax: if isinstance(response, models.query.QuerySet): output = serializers.serialize('json', response) else: output = json.dumps(response, default=json_default_handler) callback = request.GET.get('callback', False) if callback: output = '%s(%s)' % (callback, output) if request.GET.get('debug'): title = 'Rendering %(view)r in module %(app)r' % ( request.context) output = ''' <html> <head> <title>%s</title> </head> <body> <textarea>%s</textarea> </body> </html> ''' % (title, output) response = response_class(output, content_type='text/html') else: response = response_class( output, content_type='text/plain') return response else: '''Add the dictionary to the context and let render_to_response handle it''' request.context.update(response) response = None pop = True if isinstance(response, http.HttpResponse): return response elif isinstance(response, six.string_types): if request.ajax: return response_class(response, content_type='text/plain') else: return response_class(response) elif response is None: if request.jinja: # pragma: no cover assert coffin_shortcuts, ('To use Jinja the `coffin` module ' 'must be installed') render_to_string = coffin_shortcuts.render_to_string else: render_to_string = django_loader.render_to_string return response_class(render_to_string( request.template, context_instance=request.context)) else: raise UnknownViewResponseError( '"%s" is an unsupported response type' % type(response)) finally: if pop: request.context.pop()
[docs]def env(function=None, login_required=False, response_class=http.HttpResponse): ''' View decorator that automatically adds context and renders response Keyword arguments: login_required -- is everyone allowed or only authenticated users Adds a RequestContext (request.context) with the following context items: name -- current function name Stores the template in request.template and assumes it to be in <app>/<view>.html ''' def _env(request, *args, **kwargs): request.ajax = request.is_ajax() or bool(int( request.REQUEST.get('ajax', 0))) request.context = None request.jinja = getattr(settings, 'DJANGO_UTILS_USE_JINJA', False) try: name = function.__name__ app = function.__module__.split('.')[0] request = _prepare_request(request, app, name) request.template = '%s/%s.html' % (app, name) response = function(request, *args, **kwargs) return _process_response(request, response, response_class) finally: '''Remove the context reference from request to prevent leaking''' try: del request.context, request.template for k in REQUEST_PROPERTIES.keys(): # pragma: no branch delattr(request, k) except AttributeError: pass # pragma: no branch if function: _env.__name__ = function.__name__ _env.__doc__ = function.__doc__ _env.__module__ = function.__module__ _env.__dict__ = function.__dict__ if login_required: return decorators.login_required(_env) else: return _env else: return lambda f: env(f, login_required, response_class)