Permalink
Browse files

Add mirror 'applications/template_utils/'.

  • Loading branch information...
1 parent 73e74d3 commit 8b96e13cdc46dfe453af50bd0819b2b4a974800c @bryanveloso bryanveloso committed Jun 22, 2008
View
@@ -0,0 +1,7 @@
+---
+applications/template_utils:
+ local_branch: braid/svn/applications/template-utils
+ type: svn
+ revision:
+ squash: true
+ remote: http://django-template-utils.googlecode.com/svn/trunk/template_utils
No changes.
@@ -0,0 +1,32 @@
+"""
+A generic function for generating context processors, and a processor
+which adds media-specific settings to each ``RequestContext``.
+
+"""
+
+def settings_processor(*settings_list):
+ """
+ Generates and returns a context processor function which will read
+ the values of all the settings passed in and return them in each
+ ``RequestContext`` in which it is applied.
+
+ For example::
+
+ my_settings_processor = settings_processor('INTERNAL_IPS', 'SITE_ID')
+
+ ``my_settings_processor`` would then be a valid context processor
+ which would return the values of the settings ``INTERNAL_IPS`` and
+ ``SITE_ID`` in each ``RequestContext`` in which it was applied.
+
+ """
+ def _processor(request):
+ from django.conf import settings
+ settings_dict = {}
+ for setting_name in settings_list:
+ settings_dict[setting_name] = getattr(settings, setting_name)
+ return settings_dict
+ return _processor
+
+media = settings_processor('ADMIN_MEDIA_PREFIX', 'MEDIA_URL')
+media.__doc__ = """A context processor which adds the values of the settings
+``ADMIN_MEDIA_PREFIX`` and ``MEDIA_URL`` to a ``RequestContext``."""
@@ -0,0 +1,215 @@
+"""
+Utilities for text-to-HTML conversion.
+
+"""
+
+
+def textile(text, **kwargs):
+ """
+ Applies Textile conversion to a string, and returns the HTML.
+
+ This is simply a pass-through to the ``textile`` template filter
+ included in ``django.contrib.markup``, which works around issues
+ PyTextile has with Unicode strings. If you're not using Django but
+ want to use Textile with ``MarkupFormatter``, you'll need to
+ supply your own Textile filter.
+
+ """
+ from django.contrib.markup.templatetags.markup import textile
+ return textile(text)
+
+def markdown(text, **kwargs):
+ """
+ Applies Markdown conversion to a string, and returns the HTML.
+
+ """
+ import markdown
+ return markdown.markdown(text, **kwargs)
+
+def restructuredtext(text, **kwargs):
+ """
+ Applies reStructuredText conversion to a string, and returns the
+ HTML.
+
+ """
+ from docutils import core
+ parts = core.publish_parts(source=text,
+ writer_name='html4css1',
+ **kwargs)
+ return parts['fragment']
+
+DEFAULT_MARKUP_FILTERS = {
+ 'textile': textile,
+ 'markdown': markdown,
+ 'restructuredtext': restructuredtext
+ }
+
+
+class MarkupFormatter(object):
+ """
+ Generic markup formatter which can handle multiple text-to-HTML
+ conversion systems.
+
+
+ Overview
+ ========
+
+ Conversion is handled by filter functions registered with an
+ instance; a set of default filters is provided which cover
+ Markdown, reStructuredText and Textile (though using one of these
+ requires the appropriate module to be available on your system --
+ e.g., using the reST filter requires you to have ``docutils``
+ installed).
+
+ New filters can be added by registering them with an instance;
+ simply define a function which performs the conversion you want,
+ and use the ``register`` method to add it; ``register`` expects
+ two arguments:
+
+ 1. The name to associate with the filter.
+
+ 2. The actual filter function.
+
+ So, for example, you might define a new filter function called
+ ``my_filter``, and register it like so::
+
+ formatter = MarkupFormatter()
+ formatter.register('my_filter', my_filter)
+
+ Instances are callable, so applying the conversion to a string is
+ simple::
+
+ my_html = formatter(my_string, filter_name='my_filter')
+
+ The filter to use for conversion is determined in either of two
+ ways:
+
+ 1. If the keyword argument ``filter_name`` is supplied, it will be
+ used as the filter name.
+
+ 2. Absent an explicit argument, the filter name will be taken from
+ the ``MARKUP_FILTER`` setting in your Django settings file (see
+ below).
+
+ Additionally, arbitrary keyword arguments can be supplied, and
+ they will be passed on to the filter function.
+
+
+ Reading default bahavior from a Django setting
+ ==============================================
+
+ The Django setting ``MARKUP_FILTER`` can be used to specify
+ default behavior; if used, its value should be a 2-tuple:
+
+ * The first element should be the name of a filter.
+
+ * The second element should be a dictionary to use as keyword
+ arguments for that filter.
+
+ So, for example, to have the default behavior apply Markdown with
+ safe mode enabled, you would add this to your Django settings
+ file::
+
+ MARKUP_FILTER = ('markdown', { 'safe_mode': True })
+
+ The filter named in this setting does not have to be from the
+ default set; as long as you register a filter of that name before
+ trying to use the formatter, it will work.
+
+ To have the default behavior apply no conversion whatsoever, set
+ ``MARKUP_FILTER`` like so::
+
+ MARKUP_FILTER = (None, {})
+
+ When the ``filter_name`` keyword argument is supplied, the
+ ``MARKUP_FILTER`` setting is ignored entirely -- neither a filter
+ name nor any keyword arguments will be read from it. This means
+ that, by always supplying ``filter_name`` explicitly, it is
+ possible to use this formatter without configuring or even
+ installing Django.
+
+
+ Django and template autoescaping
+ ================================
+
+ Django's template system defaults to escaping the output of
+ template variables, which can interfere with functions intended to
+ return HTML. ``MarkupFormatter`` does not in any way tamper with
+ Django's autoescaping, so pasing the results of formatting
+ directly to a Django template will result in that text being
+ escaped.
+
+ If you need to use ``MarkupFormatter`` for items which will be
+ passed to a Django template as variables, use the function
+ ``django.utils.safestring.mark_safe`` to tell Django's template
+ system not to escape that text.
+
+ For convenience, a Django template filter is included (in
+ ``templatetags/generic_markup.py``) which applies
+ ``MarkupFormatter`` to a string and marks the result as not
+ requiring autoescaping.
+
+
+ Examples
+ ========
+
+ Using the default behavior, with the filter name and arguments
+ taken from the ``MARKUP_FILTER`` setting::
+
+ formatter = MarkupFormatter()
+ my_string = 'Lorem ipsum dolor sit amet.\n\nConsectetuer adipiscing elit.'
+ my_html = formatter(my_string)
+
+ Explicitly naming the filter to use::
+
+ my_html = formatter(my_string, filter_name='markdown')
+
+ Passing keyword arguments::
+
+ my_html = formatter(my_string, filter_name='markdown', safe_mode=True)
+
+ Perform no conversion (return the text as-is)::
+
+ my_html = formatter(my_string, filter_name=None)
+
+ """
+ def __init__(self):
+ self._filters = {}
+ for filter_name, filter_func in DEFAULT_MARKUP_FILTERS.items():
+ self.register(filter_name, filter_func)
+
+ def register(self, filter_name, filter_func):
+ """
+ Registers a new filter for use.
+
+ """
+ self._filters[filter_name] = filter_func
+
+ def __call__(self, text, **kwargs):
+ """
+ Applies text-to-HTML conversion to a string, and returns the
+ HTML.
+
+ """
+ if 'filter_name' in kwargs:
+ filter_name = kwargs['filter_name']
+ del kwargs['filter_name']
+ filter_kwargs = {}
+ else:
+ from django.conf import settings
+ filter_name, filter_kwargs = settings.MARKUP_FILTER
+ if filter_name is None:
+ return text
+ if filter_name not in self._filters:
+ raise ValueError("'%s' is not a registered markup filter. Registered filters are: %s." % (filter_name,
+ ', '.join(self._filters.iterkeys())))
+ filter_func = self._filters[filter_name]
+ filter_kwargs.update(**kwargs)
+ return filter_func(text, **filter_kwargs)
+
+
+# Unless you need to have multiple instances of MarkupFormatter lying
+# around, or want to subclass it, the easiest way to use it is to
+# import this instance.
+
+formatter = MarkupFormatter()
@@ -0,0 +1,72 @@
+"""
+Subclass of ``template.Node`` for easy context updating.
+
+"""
+
+from django.db.models import get_model
+from django.conf import settings
+from django import template
+
+
+class ContextUpdatingNode(template.Node):
+ """
+ Node that updates the context with certain values.
+
+ Subclasses should define ``get_content()``, which should return a
+ dictionary to be added to the context.
+
+ """
+ def render(self, context):
+ context.update(self.get_content(context))
+ return ''
+
+ def get_content(self, context):
+ raise NotImplementedError
+
+
+class GenericContentNode(ContextUpdatingNode):
+ """
+ Base Node class for retrieving objects from any model.
+
+ By itself, this class will retrieve a number of objects from a
+ particular model (specified by an "app_name.model_name" string)
+ and store them in a specified context variable (these are the
+ ``num``, ``model`` and ``varname`` arguments to the constructor,
+ respectively), but is also intended to be subclassed for
+ customization.
+
+ There are two ways to add extra bits to the eventual database
+ lookup:
+
+ 1. Add the setting ``GENERIC_CONTENT_LOOKUP_KWARGS`` to your
+ settings file; this should be a dictionary whose keys are
+ "app_name.model_name" strings corresponding to models, and whose
+ values are dictionaries of keyword arguments which will be
+ passed to ``filter()``.
+
+ 2. Subclass and override ``_get_query_set``; all that's expected
+ is that it will return a ``QuerySet`` which will be used to
+ retrieve the object(s). The default ``QuerySet`` for the
+ specified model (filtered as described above) will be available
+ as ``self.query_set`` if you want to work with it.
+
+ """
+ def __init__(self, model, num, varname):
+ self.num = num
+ self.varname = varname
+ lookup_dict = getattr(settings, 'GENERIC_CONTENT_LOOKUP_KWARGS', {})
+ self.model = get_model(*model.split('.'))
+ if self.model is None:
+ raise template.TemplateSyntaxError("Generic content tag got invalid model: %s" % model)
+ self.query_set = self.model._default_manager.filter(**lookup_dict.get(model, {}))
+
+ def _get_query_set(self):
+ return self.query_set
+
+ def get_content(self, context):
+ query_set = self._get_query_set()
+ if self.num == 1:
+ result = query_set[0]
+ else:
+ result = list(query_set[:self.num])
+ return { self.varname: result }
Oops, something went wrong.

0 comments on commit 8b96e13

Please sign in to comment.