+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': 'db.sl3'
+ }
+}
\ No newline at end of file
--- /dev/null
+Exceptions
+==========
+
+.. automodule:: philo.exceptions
+ :members: MIDDLEWARE_NOT_CONFIGURED, AncestorDoesNotExist, ViewCanNotProvideSubpath, ViewDoesNotProvideSubpaths
\ No newline at end of file
intro
models/intro
+ exceptions
+ middleware
+ signals
+ validators
Indices and tables
==================
--- /dev/null
+Middleware
+==========
+
+.. automodule:: philo.middleware
+ :members:
:members:
EntityProxyFields
-=================
+-----------------
.. automodule:: philo.models.fields.entities
:members:
\ No newline at end of file
--- /dev/null
+Signals
+=======
+
+.. automodule:: philo.signals
+ :members:
--- /dev/null
+Validators
+==========
+
+.. automodule:: philo.validators
+ :members:
from django.forms.models import model_to_dict
from philo.models import TreeEntity, Node, TreeManager, Entity, TargetURLModel
-from philo.validators import RedirectValidator
DEFAULT_NAVIGATION_DEPTH = 3
from django.conf.urls.defaults import patterns, url
from django.contrib import messages
from django.core.exceptions import ValidationError
+from django.core.validators import URLValidator
from django.db import models
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.utils import simplejson as json
from philo.exceptions import ViewCanNotProvideSubpath
from philo.models import MultiView, Page
from philo.models.fields import SlugMultipleChoiceField
-from philo.validators import RedirectValidator
eventlet = None
if getattr(settings, 'SOBOL_USE_EVENTLET', False):
class ResultURL(models.Model):
search = models.ForeignKey(Search, related_name='result_urls')
- url = models.TextField(validators=[RedirectValidator()])
+ url = models.TextField(validators=[URLValidator()])
def __unicode__(self):
return self.url
{% block content %}
<div class="container-grid delete-confirmation">
{% for search in queryset %}
- {% if not forloop.first and not forloop.last %}<h1>{{ search.string }}</h1>{% endif %}
<div class="group tabular">
- <h2>{% blocktrans %}Results{% endblocktrans %}</h2>{% comment %}For the favored results, add a class?{% endcomment %}
+ <h2>{{ search_string }}</h2>
<div class="module table">
<div class="module thead">
<div class="tr">
{% block content %}
{% for search in queryset %}
- {% if not forloop.first and not forloop.last %}<h1>{{ search.string }}</h1>{% endif %}
<fieldset class="module">
- <h2>{% blocktrans %}Results{% endblocktrans %}</h2>{% comment %}For the favored results, add a class?{% endcomment %}
+ <h2>{{ search.string }}</h2>
<table>
<thead>
<tr>
from django.core.exceptions import ImproperlyConfigured
+#: Raised if ``request.node`` is required but not present. For example, this can be raised by :func:`philo.views.node_view`. :data:`MIDDLEWARE_NOT_CONFIGURED` is an instance of :exc:`django.core.exceptions.ImproperlyConfigured`.
MIDDLEWARE_NOT_CONFIGURED = ImproperlyConfigured("""Philo requires the RequestNode middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'philo.middleware.RequestNodeMiddleware'.""")
class ViewDoesNotProvideSubpaths(Exception):
- """ Raised by View.reverse when the View does not provide subpaths (the default). """
+ """Raised by :meth:`View.reverse` when the View does not provide subpaths (the default)."""
silent_variable_failure = True
class ViewCanNotProvideSubpath(Exception):
- """ Raised by View.reverse when the View can not provide a subpath for the supplied arguments. """
+ """Raised by :meth:`View.reverse` when the :class:`View` can not provide a subpath for the supplied arguments."""
silent_variable_failure = True
class AncestorDoesNotExist(Exception):
- """ Raised by get_path if the root model is not an ancestor of the current model """
+ """Raised by :meth:`TreeModel.get_path` if the root instance is not an ancestor of the current instance."""
pass
\ No newline at end of file
class RequestNodeMiddleware(object):
- """Middleware to process the request's path and attach the closest ancestor node."""
+ """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 get_with_path(self, path, root=None, absolute_result=True, pathsep='/', field='slug'):
"""
- If ``absolute_result`` is ``True``, returns the object at ``path`` (starting at ``root``) or raises a :class:`DoesNotExist` exception. Otherwise, returns a tuple containing the deepest object found along ``path`` (or ``root`` if no deeper object is found) and the remainder of the path after that object as a string (or None if there is no remaining path).
+ If ``absolute_result`` is ``True``, returns the object at ``path`` (starting at ``root``) or raises an :class:`~django.core.exceptions.ObjectDoesNotExist` exception. Otherwise, returns a tuple containing the deepest object found along ``path`` (or ``root`` if no deeper object is found) and the remainder of the path after that object as a string (or None if there is no remaining path).
.. note:: If you are looking for something with an exact path, it is faster to use absolute_result=True, unless the path depth is over ~40, in which case the high cost of the absolute query may make a binary search (i.e. non-absolute) faster.
:param absolute_result: Whether to return an absolute result or do a binary search
:param pathsep: The path separator used in ``path``
:param field: The field on the model which should be queried for ``path`` segment matching.
- :returns: An instance if absolute_result is True or (instance, remaining_path) otherwise.
+ :returns: An instance if ``absolute_result`` is ``True`` or an (instance, remaining_path) tuple otherwise.
+ :raises django.core.exceptions.ObjectDoesNotExist: if no object can be found matching the input parameters.
"""
from philo.models.base import TreeEntity, Entity, register_value_model
from philo.models.fields import JSONField
from philo.utils import ContentTypeSubclassLimiter, LazyPassthroughAttributeMapper
-from philo.validators import RedirectValidator
from philo.signals import view_about_to_render, view_finished_rendering
If ``obj`` is provided, :meth:`get_reverse_params` will be called and the results will be combined with any ``view_name``, ``args``, and ``kwargs`` that may have been passed in.
- This method will raise the following exceptions:
-
- - :class:`~philo.exceptions.ViewDoesNotProvideSubpaths` if :attr:`accepts_subpath` is False.
- - :class:`~philo.exceptions.ViewCanNotProvideSubpath` if a reversal is not possible.
-
:param view_name: The name of the view to be reversed.
:param args: Extra args for reversing the view.
:param kwargs: A dictionary of arguments for reversing the view.
:param node: The node whose subpath this is.
:param obj: An object to be passed to :meth:`get_reverse_params` to generate a view_name, args, and kwargs for reversal.
:returns: A subpath beyond the node that reverses the view, or an absolute url that reverses the view if a node was passed in.
+ :except philo.exceptions.ViewDoesNotProvideSubpaths: if :attr:`accepts_subpath` is False
+ :except philo.exceptions.ViewCanNotProvideSubpath: if a reversal is not possible.
"""
if not self.accepts_subpath:
"""An abstract parent class for models which deal in targeting a url."""
#: An optional :class:`ForeignKey` to a :class:`Node`. If provided, that node will be used as the basis for the redirect.
target_node = models.ForeignKey(Node, blank=True, null=True, related_name="%(app_label)s_%(class)s_related")
- #: A :class:`CharField` which may contain an absolute or relative URL. This will be validated with :class:`philo.validators.RedirectValidator`.
- url_or_subpath = models.CharField(max_length=200, validators=[RedirectValidator()], blank=True, help_text="Point to this url or, if a node is defined and accepts subpaths, this subpath of the node.")
+ #: A :class:`CharField` which may contain an absolute or relative URL, or the name of a node's subpath.
+ url_or_subpath = models.CharField(max_length=200, blank=True, help_text="Point to this url or, if a node is defined and accepts subpaths, this subpath of the node.")
#: A :class:`~philo.models.fields.JSONField` instance. If the value of :attr:`reversing_parameters` is not None, the :attr:`url_or_subpath` will be treated as the name of a view to be reversed. The value of :attr:`reversing_parameters` will be passed into the reversal as args if it is a list or as kwargs if it is a dictionary. Otherwise it will be ignored.
reversing_parameters = JSONField(blank=True, help_text="If reversing parameters are defined, url_or_subpath will instead be interpreted as the view name to be reversed.")
from django.dispatch import Signal
+#: Sent whenever an Entity subclass has been "prepared" -- that is, after the processing necessary to make :mod:`EntityProxyFields <philo.models.fields.entities>` work has been completed. This will fire after :obj:`django.db.models.signals.class_prepared`.
+#:
+#: Arguments that are sent with this signal:
+#:
+#: ``sender``
+#: The model class.
entity_class_prepared = Signal(providing_args=['class'])
+
+#: Sent when a :class:`~philo.models.nodes.View` instance is about to render. This allows you, for example, to modify the ``extra_context`` dictionary used in rendering.
+#:
+#: Arguments that are sent with this signal:
+#:
+#: ``sender``
+#: The :class:`~philo.models.nodes.View` instance
+#:
+#: ``request``
+#: The :class:`HttpRequest` instance which the :class:`~philo.models.nodes.View` is rendering in response to.
+#:
+#: ``extra_context``
+#: A dictionary which will be passed into :meth:`~philo.models.nodes.View.actually_render_to_response`.
view_about_to_render = Signal(providing_args=['request', 'extra_context'])
+
+#: Sent when a view instance has finished rendering.
+#:
+#: Arguments that are sent with this signal:
+#:
+#: ``sender``
+#: The :class:`~philo.models.nodes.View` instance
+#:
+#: ``response``
+#: The :class:`HttpResponse` instance which :class:`~philo.models.nodes.View` view has rendered to.
view_finished_rendering = Signal(providing_args=['response'])
+
+#: Sent when a :class:`~philo.models.pages.Page` instance is about to render as a string. If the :class:`~philo.models.pages.Page` is rendering as a response, this signal is sent after :obj:`view_about_to_render` and serves a similar function. However, there are situations where a :class:`~philo.models.pages.Page` may be rendered as a string without being rendered as a response afterwards.
+#:
+#: Arguments that are sent with this signal:
+#:
+#: ``sender``
+#: The :class:`~philo.models.pages.Page` instance
+#:
+#: ``request``
+#: The :class:`HttpRequest` instance which the :class:`~philo.models.pages.Page` is rendering in response to (if any).
+#:
+#: ``extra_context``
+#: A dictionary which will be passed into the :class:`Template` context.
page_about_to_render_to_string = Signal(providing_args=['request', 'extra_context'])
+
+#: Sent when a :class:`~philo.models.pages.Page` instance has just finished rendering as a string. If the :class:`~philo.models.pages.Page` is rendering as a response, this signal is sent before :obj:`view_finished_rendering` and serves a similar function. However, there are situations where a :class:`~philo.models.pages.Page` may be rendered as a string without being rendered as a response afterwards.
+#:
+#: Arguments that are sent with this signal:
+#:
+#: ``sender``
+#: The :class:`~philo.models.pages.Page` instance
+#:
+#: ``string``
+#: The string which the :class:`~philo.models.pages.Page` has rendered to.
page_finished_rendering_to_string = Signal(providing_args=['string'])
\ No newline at end of file
import re
from django.core.exceptions import ValidationError
-from django.core.validators import RegexValidator
from django.template import Template, Parser, Lexer, TOKEN_BLOCK, TOKEN_VAR, TemplateSyntaxError
from django.utils import simplejson as json
from django.utils.html import escape, mark_safe
from philo.utils import LOADED_TEMPLATE_ATTR
+#: Tags which are considered insecure and are therefore always disallowed by secure :class:`TemplateValidator` instances.
INSECURE_TAGS = (
'load',
'extends',
)
-class RedirectValidator(RegexValidator):
- """Based loosely on the URLValidator, but no option to verify_exists"""
- regex = re.compile(
- r'^(?:https?://' # http:// or https://
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
- r'localhost|' #localhost...
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
- r'(?::\d+)?' # optional port
- r'(?:/?|[/?#]?\S+)|'
- r'[^?#\s]\S*)$',
- re.IGNORECASE)
- message = _(u'Enter a valid absolute or relative redirect target')
-
-
-class URLLinkValidator(RegexValidator):
- """Based loosely on the URLValidator, but no option to verify_exists"""
- regex = re.compile(
- r'^(?:https?://' # http:// or https://
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
- r'localhost|' #localhost...
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
- r'(?::\d+)?' # optional port
- r'|)' # also allow internal links
- r'(?:/?|[/?#]?\S+)$', re.IGNORECASE)
- message = _(u'Enter a valid absolute or relative redirect target')
-
-
def json_validator(value):
+ """Validates whether ``value`` is a valid json string."""
try:
json.loads(value)
except Exception, e:
class TemplateValidator(object):
+ """
+ Validates whether a string represents valid Django template code.
+
+ :param allow: ``None`` or an iterable of tag names which are explicitly allowed. If provided, tags whose names are not in the iterable will cause a ValidationError to be raised if they are used in the template code.
+ :param disallow: ``None`` or an iterable of tag names which are explicitly allowed. If provided, tags whose names are in the iterable will cause a ValidationError to be raised if they are used in the template code. If a tag's name is in ``allow`` and ``disallow``, it will be disallowed.
+ :param secure: If the validator is set to secure, it will automatically disallow the tag names listed in :const:`INSECURE_TAGS`. Defaults to ``True``.
+
+ """
def __init__(self, allow=None, disallow=None, secure=True):
self.allow = allow
self.disallow = disallow