X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/ed6b9876b7abff0b2dc6266d6f769c319f358a9c..c5586d632dc2cf5b06af929b2cb38131042c0ed6:/philo/middleware.py diff --git a/philo/middleware.py b/philo/middleware.py index 5ec3e77..f4f7e9d 100644 --- a/philo/middleware.py +++ b/philo/middleware.py @@ -1,57 +1,54 @@ from django.conf import settings from django.contrib.sites.models import Site from django.http import Http404 + from philo.models import Node, View +from philo.utils.lazycompat import SimpleLazyObject -class LazyNode(object): - def __get__(self, request, obj_type=None): - if not hasattr(request, '_cached_node_path'): - return None - - if not hasattr(request, '_found_node'): - try: - current_site = Site.objects.get_current() - except Site.DoesNotExist: - current_site = None - - path = request._cached_node_path - trailing_slash = False - if path[-1] == '/': - trailing_slash = True - - try: - node, subpath = Node.objects.get_with_path(path, root=getattr(current_site, 'root_node', None), absolute_result=False) - except Node.DoesNotExist: - node = None - else: - if subpath is None: - subpath = "" - subpath = "/" + subpath - - if not node.handles_subpath(subpath): - node = None - else: - if trailing_slash and subpath[-1] != "/": - subpath += "/" - - node.subpath = subpath - - request._found_node = node - - return request._found_node +def get_node(path): + """Returns a :class:`Node` instance at ``path`` (relative to the current site) or ``None``.""" + try: + current_site = Site.objects.get_current() + except Site.DoesNotExist: + current_site = None + + trailing_slash = False + if path[-1] == '/': + trailing_slash = True + + try: + node, subpath = Node.objects.get_with_path(path, root=getattr(current_site, 'root_node', None), absolute_result=False) + except Node.DoesNotExist: + return None + + if subpath is None: + subpath = "" + subpath = "/" + subpath + + if trailing_slash and subpath[-1] != "/": + subpath += "/" + + node._path = path + node._subpath = subpath + + return node class RequestNodeMiddleware(object): - """Middleware to process the request's path and attach the closest ancestor node.""" - def process_request(self, request): - request.__class__.node = LazyNode() + """ + Adds a ``node`` attribute, representing the currently-viewed :class:`.Node`, to every incoming :class:`HttpRequest` object. This is required by :func:`philo.views.node_view`. + :class:`RequestNodeMiddleware` also catches all exceptions raised while handling requests that have attached :class:`.Node`\ s if :setting:`settings.DEBUG` is ``True``. If a :exc:`django.http.Http404` error was caught, :class:`RequestNodeMiddleware` will look for an "Http404" :class:`.Attribute` on the request's :class:`.Node`; otherwise it will look for an "Http500" :class:`.Attribute`. If an appropriate :class:`.Attribute` is found, and the value of the attribute is a :class:`.View` instance, then the :class:`.View` will be rendered with the exception in the ``extra_context``, bypassing any later handling of exceptions. + + """ def process_view(self, request, view_func, view_args, view_kwargs): try: - request._cached_node_path = view_kwargs['path'] + path = view_kwargs['path'] except KeyError: - pass + request.node = None + else: + request.node = SimpleLazyObject(lambda: get_node(path)) def process_exception(self, request, exception): if settings.DEBUG or not hasattr(request, 'node') or not request.node: @@ -59,12 +56,16 @@ class RequestNodeMiddleware(object): if isinstance(exception, Http404): error_view = request.node.attributes.get('Http404', None) + status_code = 404 else: error_view = request.node.attributes.get('Http500', None) + status_code = 500 if error_view is None or not isinstance(error_view, View): # Should this be duck-typing? Perhaps even no testing? return extra_context = {'exception': exception} - return error_view.render_to_response(request, extra_context) \ No newline at end of file + response = error_view.render_to_response(request, extra_context) + response.status_code = status_code + return response \ No newline at end of file