-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add mirror 'applications/template_utils/'.
- Loading branch information
1 parent
73e74d3
commit 8b96e13
Showing
10 changed files
with
762 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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``.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } |
Empty file.
Oops, something went wrong.