language = settings.LANGUAGE_CODE.decode(),
feed_url = add_domain(
current_site.domain,
- self.__get_dynamic_attr('feed_url', obj) or node.construct_url(node.subpath, with_domain=True, request=request, secure=request.is_secure()),
+ self.__get_dynamic_attr('feed_url', obj) or node.construct_url(node._subpath, with_domain=True, request=request, secure=request.is_secure()),
request.is_secure()
),
author_name = self.__get_dynamic_attr('author_name', obj),
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):
"""Adds a ``node`` attribute, representing the currently-viewed node, to every incoming :class:`HttpRequest` object. This is required by :func:`philo.views.node_view`."""
- def process_request(self, request):
- request.__class__.node = LazyNode()
-
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:
"""
clear_url_caches()
- subpath = request.node.subpath
+ subpath = request.node._subpath
view, args, kwargs = resolve(subpath, urlconf=self)
view_args = getargspec(view)
if extra_context is not None and ('extra_context' in view_args[0] or view_args[2] is not None):
--- /dev/null
+try:
+ from django.utils.functional import empty, LazyObject, SimpleLazyObject
+except ImportError:
+ # Supply LazyObject and SimpleLazyObject for django < r16308
+ import operator
+
+
+ empty = object()
+ def new_method_proxy(func):
+ def inner(self, *args):
+ if self._wrapped is empty:
+ self._setup()
+ return func(self._wrapped, *args)
+ return inner
+
+ class LazyObject(object):
+ """
+ A wrapper for another class that can be used to delay instantiation of the
+ wrapped class.
+
+ By subclassing, you have the opportunity to intercept and alter the
+ instantiation. If you don't need to do that, use SimpleLazyObject.
+ """
+ def __init__(self):
+ self._wrapped = empty
+
+ __getattr__ = new_method_proxy(getattr)
+
+ def __setattr__(self, name, value):
+ if name == "_wrapped":
+ # Assign to __dict__ to avoid infinite __setattr__ loops.
+ self.__dict__["_wrapped"] = value
+ else:
+ if self._wrapped is empty:
+ self._setup()
+ setattr(self._wrapped, name, value)
+
+ def __delattr__(self, name):
+ if name == "_wrapped":
+ raise TypeError("can't delete _wrapped.")
+ if self._wrapped is empty:
+ self._setup()
+ delattr(self._wrapped, name)
+
+ def _setup(self):
+ """
+ Must be implemented by subclasses to initialise the wrapped object.
+ """
+ raise NotImplementedError
+
+ # introspection support:
+ __members__ = property(lambda self: self.__dir__())
+ __dir__ = new_method_proxy(dir)
+
+
+ class SimpleLazyObject(LazyObject):
+ """
+ A lazy object initialised from any function.
+
+ Designed for compound objects of unknown type. For builtins or objects of
+ known type, use django.utils.functional.lazy.
+ """
+ def __init__(self, func):
+ """
+ Pass in a callable that returns the object to be wrapped.
+
+ If copies are made of the resulting SimpleLazyObject, which can happen
+ in various circumstances within Django, then you must ensure that the
+ callable can be safely run more than once and will return the same
+ value.
+ """
+ self.__dict__['_setupfunc'] = func
+ super(SimpleLazyObject, self).__init__()
+
+ def _setup(self):
+ self._wrapped = self._setupfunc()
+
+ __str__ = new_method_proxy(str)
+ __unicode__ = new_method_proxy(unicode)
+
+ def __deepcopy__(self, memo):
+ if self._wrapped is empty:
+ # We have to use SimpleLazyObject, not self.__class__, because the
+ # latter is proxied.
+ result = SimpleLazyObject(self._setupfunc)
+ memo[id(self)] = result
+ return result
+ else:
+ import copy
+ return copy.deepcopy(self._wrapped, memo)
+
+ # Need to pretend to be the wrapped class, for the sake of objects that care
+ # about this (especially in equality tests)
+ __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
+ __eq__ = new_method_proxy(operator.eq)
+ __hash__ = new_method_proxy(hash)
+ __nonzero__ = new_method_proxy(bool)
\ No newline at end of file
raise Http404
node = request.node
- subpath = request.node.subpath
+ subpath = request.node._subpath
# Explicitly disallow trailing slashes if we are otherwise at a node's url.
- if request._cached_node_path != "/" and request._cached_node_path[-1] == "/" and subpath == "/":
+ if node._path != "/" and node._path[-1] == "/" and subpath == "/":
return HttpResponseRedirect(node.get_absolute_url())
if not node.handles_subpath(subpath):