Commits

Anonymous committed 2d440aa

Swapped around some README formatting.

Comments (0)

Files changed (3)

+<!--*-markdown-*-->
+# DjanJinja v0.6
+
+DjanJinja: the sound you make when you've got peanut butter stuck to the roof of
+your mouth. Incidentally, it also happens to be the name of a new re-usable
+Django app. This one, in fact.
+
+DjanJinja exists to help you leverage the power of
+[Jinja2](http://jinja.pocoo.org/2/) templates in your Django projects. It's
+simple to get started.
+
+## Installing and Using DjanJinja
+
+### Installing DjanJinja
+
+1. Install DjanJinja using `easy_install djanjinja`, `pip install djanjinja`, or
+   by grabbing a copy of the Mercurial repo and running `python setup.py
+   install`.
+2. Add `'djanjinja'` to your `INSTALLED_APPS` list.
+3. (Optionally) add `'djanjinja.middleware.RequestContextMiddleware'` to your
+   `MIDDLEWARE_CLASSES` list.
+
+It’s assumed that you have fairly recent versions of Jinja2 and Django
+installed. The author recommends the *most recent* stable versions of each,
+which should be installable via PyPI (i.e. a simple `easy_install` or `pip
+install`). A lot of people have their own ways of installing things, so the
+author hasn’t put any explicit requirements in the `setup.py` file. DjanJinja
+just expects to find `jinja2` and `django` on the import path.
+
+### Using DjanJinja
+
+* Instead of using `django.shortcuts.render_to_response`, use one of the
+  Jinja2-based functions provided.
+* Instead of using the Django loaders to load templates, get them from the
+  Jinja2 environment created for you by DjanJinja.
+* Instead of using Django’s provided generic views, use those contained within
+  `djanjinja.generic` (at the moment the only one is `direct_to_template()`).
+
+## Shortcut Functions
+
+DjanJinja provides you with two shortcut functions for rendering templates,
+`render_to_response` and `render_to_string`. These are very similar to those
+provided by Django in the `django.shortcuts` module, except they use Jinja2
+instead of the Django templating system. To use them from your views, just do
+`from djanjinja.views import render_to_response, render_to_string` at the top of
+your views module.
+
+## Bundles
+
+A Jinja2 environment can contain additional filters, tests and global variables
+which will be available in all templates rendered through that environment.
+Since individual Django apps will have their own set of things to add to the
+environment, DjanJinja adds the concept of ‘bundles’; small objects containing
+some global variables, filters and tests. Each app may define any number of
+these bundles which can then be loaded as required.
+
+### Defining Bundles
+
+It’s relatively easy to define a bundle; an example is shown below:
+    
+    from djanjinja.loader import Bundle
+    
+    foo = Bundle()
+    foo.globals['myvar'] = 12345
+    
+    @foo.envfilter
+    def myenvfilter(environment, value):
+        pass # do something here...
+    
+    @foo.ctxfunction
+    def mycontextfunction(context, value):
+        pass # do something here...
+
+Here we define a bundle called `foo`, with a global variable of `myvar`
+containing the value `12345`, an environment filter and a context function (for
+more information on each of these please consult the Jinja2 documentation). The
+`Bundle` class also supplies these handy decorators (the full list can be found
+as `djanjinja.loader.Bundle.TYPES`) to define various components.
+
+DjanJinja expects to find bundles in a `bundles` submodule of your Django app.
+You can lay things out in one of two ways:
+
+* Add a file called `bundles.py` to your app, and within this define multiple
+  `Bundle` instances.
+* Add a package called `bundles` to your app (i.e. a `bundles` directory
+  containing an empty file called `__init__.py`), and within this define
+  submodules for each of your bundles. Each submodule should have a top-level
+  `bundle` variable which is an instance of the `Bundle` class.
+
+You can actually mix and match these; you could add some bundle instances to the
+`bundles/__init__.py` file with different names, in addition to having the
+submodules. These are loaded lazily, so DjanJinja sees no real difference. It
+doesn’t scour the `bundles` module for definitions, it just loads what you ask
+it to.
+
+### Addressing Bundles
+
+In order to use the functions, filters and tests defined in a bundle, you first
+have to load it into the environment. Bundles are specified in two parts: the
+‘app label’ and the ‘bundle name’. The app label is simply the name of the app
+which contains it. For example, it may be `django.contrib.auth`, or simply
+`auth`, since you may just give the last part of the full name and DjanJinja
+will figure it out from looking at the `INSTALLED_APPS` setting.
+
+If a bundle is defined within a `bundles.py` or a `bundles/__init__.py` file,
+then the bundle name will be the name in the module with which it was defined.
+For example:
+    
+    # in the file `myapp/bundles.py`
+    foo = Bundle()
+    foo.globals['myvar'] = 12345
+
+In this case, the app label will be `myapp`, and the bundle name will be `foo`.
+If the bundles are defined in submodules, then the bundle name will be the name
+of the submodule.
+
+### Loading Bundles
+
+In order to load any bundles into the global Jinja2 environment, you need to specify a
+`DJANJINJA_BUNDLES` setting in your `settings.py` file. This is a list or tuple
+of bundle specifiers in an `'app_label.bundle_name'` format. For example:
+
+    DJANJINJA_BUNDLES = (
+        'djanjinja.cache',
+        'djanjinja.humanize',
+        'djanjinja.site',
+    )
+
+You can also add bundles to the environment programmatically. This is useful
+when:
+
+* Your app needs to do some initial setup before a bundle is loaded.
+* Your app relies on a particular bundle being present in the global environment
+  anyway, and you don’t want the user to have to add the bundle to
+  `DJANJINJA_BUNDLES` manually.
+* Your app needs to load bundles dynamically.
+* Your app wants to use a bundle locally, not globally.
+
+You can load a bundle into an environment like this:
+
+    import djanjinja
+    env = djanjinja.get_env()
+    env.load('app_label', 'bundle_name', reload=False)
+
+This will load the bundle into the environment, passing through if it’s already
+loaded. If you specify `reload=True`, you can make it reload a bundle even if
+it’s been loaded.
+
+You should put this code somewhere where it will get executed when you want it
+to. If you want it to be executed immediately, as Django starts up, put it in
+`myapp/__init__.py`.
+
+You can also use a bundle within only one app, by using a local environment
+copied from the global environment. Here’s how you might do this:
+
+    import djanjinja
+    global_env = djanjinja.get_env()
+    local_env = global_env.copy()
+    local_env.load('app_label', 'bundle_name')
+
+You'd then use that local environment later on in your code. For example, the
+above code might be in `myapp/__init__.py`; so your views might look like this:
+
+    from django.http import HttpResponse
+    from myapp import local_env
+    
+    def view(request):
+        template = local_env.get_template('template_name.html')
+        data = template.render({'key1': 'value1', 'key2': 'value2'})
+        return HttpResponse(content=data)
+
+Of course, you’re probably going to want to use the usual shortcuts (i.e.
+`render_to_response()` and `render_to_string()`). You can build these easily
+using `djanjinja.views.shortcuts_for_environment()`:
+
+    from djanjinja.views import shortcuts_for_environment
+    
+    render_to_response, render_to_string = shortcuts_for_environment(local_env)
+
+Do this at the top of your `views.py` file, and then you can use the generated
+functions throughout all of your views.
+
+### Caveats and Limitations
+
+Jinja2 does not yet support scoped filters and tests; as a result of this, the
+contents of bundles specified in `DJANJINJA_BUNDLES` will be loaded into the global environment. It is important
+to make sure that definitions in your bundle do not override those in another
+bundle. This is especially important with threaded web applications, as multiple
+bundles overriding one another could cause unpredictable behavior in the
+templates.
+
+### Included Bundles
+
+DjanJinja provides three bundles already which either replace Django
+counterparts or add some useful functionality to your Jinja2 templates:
+    
+* `djanjinja.cache`: Loading this bundle will add a global `cache` object to the
+  environment; this is the Django cache, and allows you to carry out caching
+  operations from within your templates (such as `cache.get(key)`, et cetera).
+
+* `djanjinja.humanize`: This will add all of the filters contained within the
+  `django.contrib.humanize` app; consult the official Django docs for more
+  information on the filters provided.
+
+* `djanjinja.site`: This will add two functions to the global environment:
+  `url`, and `setting`. The former acts like Django’s template tag, by reversing
+  URLconf names and views into URLs, but because Jinja2 supports a richer
+  syntax, it can be used via `{{ url(name, *args, **kwargs) }}` instead.
+  `setting` attempts to resolve a setting name into a value, returning an
+  optional default instead (i.e. `setting('MEDIA_URL', '/media')`).
+
+## Extensions
+
+Jinja2 supports the concept of *environment extensions*; these are non-trivial
+plugins which enhance the Jinja2 templating engine itself. By default, the
+environment is configured with the `do` statement and the loop controls (i.e.
+`break` and `continue`), but if you want to add extensions to the environment
+then you can do so with the `JINJA_EXTENSIONS` setting. Just add this to your
+`settings.py` file:
+    
+    JINJA_EXTENSIONS = (
+        'jinja2.ext.i18n', # i18n Extension
+        ...
+    )
+
+For all the extensions you wish to load. This will be passed in directly to the
+`jinja2.Environment` constructor.
+
+If you have set `USE_I18N = True` in your settings file, then DjanJinja will
+automatically initialize the i18n machinery for the Jinja2 environment, loading
+your Django translations during the bootstrapping process. For more information
+on how to use the Jinja2 i18n extension, please consult the Jinja2
+documentation.
+
+### Cache
+
+DjanJinja also provides an extension for fragment caching using the Django cache
+system. The code for this borrows heavily from the example in the Jinja2
+documentation, but with a few extras thrown in. You can use the extension like
+this:
+    
+    {% cache (parameter1, param2, param3), timeout %}
+        ...
+    {% endcache %}
+
+The tuple of parameters is used to generate the cache key for this fragment. You
+can place any object here, so long as it is suitable for serialization by the
+standard library `marshal` module. The cache key for the fragment is generated
+by marshaling the parameters, hashing them and then using the digest with a
+prefix as the key. This allows you to specify cached fragments which vary
+depending on multiple variables. The timeout is optional, and should be given in
+seconds.
+
+## 404 and 500 Handlers
+
+Your project’s URLconf must specify two variables—`handler404` and `handler500`—which give the name of a Django view to be processed in the event of a 404 "Not Found" and a 500 "Server Error" response respectively. These are set to a default which uses the Django templating system to render a response from templates called `404.html` and `500.html`. If you were to use the Jinja2 templating system instead, you will be able to define richer error pages, and your error pages will be able to inherit from and extend other Jinja2 master templates on the template path.
+
+It’s relatively simple to set Django up to do this. Simply override the handler variables like so from your `urls.py` file:
+
+    handler404 = 'djanjinja.handlers.page_not_found'
+    handler500 = 'djanjinja.handlers.server_error'
+
+## `RequestContext`
+
+One of Django's most useful features is the `RequestContext` class, which allows
+you to specify several context processors which each add some information to the
+context before templates are rendered. Luckily, this feature is
+template-agnostic, and is therefore fully compatible with DjanJinja.
+
+However, DjanJinja also provides you with some very helpful shortcuts for using
+request contexts. Usually, without DjanJinja, you would use them like this:
+    
+    from django.shortcuts import render_to_response
+    from django.template import RequestContext
+    
+    def myview(request):
+        context = {'foo': bar, 'spam': eggs}
+        return render_to_response('template_name.html',
+            context, context_instance=RequestContext())
+
+To be honest,this doesn't look very much like a 'shortcut' at all. For this
+reason, DjanJinja contains a subclass of `RequestContext` specialised for
+Jinja2, which is used like this:
+
+    from djanjinja.views import RequestContext
+    
+    def myview(request):
+        context = RequestContext(request, {'foo': bar, 'spam': eggs})
+        return context.render_response('template_name.html')
+
+This code is much more concise, but loses none of the flexibility of the
+previous example. The main changes made are the addition of `render_response`
+and `render_string` methods to the context object itself. This is highly
+specialised to rendering Jinja2 templates, so it may not be a very reusable
+approach (indeed, other code which does not use Jinja2 will need to use the full
+Django syntax), but it works for the problem domain it was designed for.
+
+## Middleware
+
+One important thing to note from before is that each time a `RequestContext`
+instance is constructed, it is necessary to explicitly pass the request. In
+object-oriented programming, and Python expecially, when we have functions to
+which we must always pass an object of a certain type, it makes sense to make
+that function a *method* of the type. When that function is not, in fact, a
+function, but a constructor, this seems more difficult. However, thanks to a
+feature of Python known as metaprogramming, we can do this very easily. Because
+it's not exactly obvious how to do so, DjanJinja includes a special piece of
+middleware which can help make your code a lot shorter yet *still* retain all
+the functionality and flexibility of the previous two examples.
+
+To use this middleware, simply add
+`'djanjinja.middleware.RequestContextMiddleware'` to your `MIDDLEWARE_CLASSES`
+list in the settings module of your project. Then, you can write view code like
+this:
+
+    def myview(request):
+        return request.Context({'foo': bar, 'spam': eggs}).render_response(
+            'template_name.html')
+
+As you can see, we've greatly reduced the verbosity of the previous code, but
+it's still obvious what this code does. The middleware attaches a `Context`
+attribute to each request object. This attribute is in fact a fully-fledged
+Python class, which may itself be subclassed and modified later on. When
+constructed, it behaves almost exactly the same as the usual `RequestContext`,
+only it uses the request object to which it has been attached, so you don't have
+to pass it in to the constructor every time.
+
+## Template Loading
+
+DjanJinja hooks directly into the Django template loader machinery to load
+templates. This means you can mix Jinja2 templates freely with Django templates,
+in your `TEMPLATE_DIRS` and your applications, and render each type
+independently and seamlessly. If you want more information on how it actually
+works, please consult the `djanjinja/environment.py` file.
+
+## License
+
+This software is licensed under the following MIT-style license:
+    
+> Copyright (c) 2009 Zachary Voase
+> 
+> Permission is hereby granted, free of charge, to any person
+> obtaining a copy of this software and associated documentation
+> files (the "Software"), to deal in the Software without
+> restriction, including without limitation the rights to use,
+> copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the
+> Software is furnished to do so, subject to the following
+> conditions:
+> 
+> The above copyright notice and this permission notice shall be
+> included in all copies or substantial portions of the Software.
+> 
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+> OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+> HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+> OTHER DEALINGS IN THE SOFTWARE.
+
+## Author
+
+Zachary Voase can be found on [Twitter](http://twitter.com/zacharyvoase).

README.html

-<h1>DjanJinja v0.6</h1>
-
-<p>DjanJinja: the sound you make when you&#8217;ve got peanut butter stuck to the roof of
-your mouth. Incidentally, it also happens to be the name of a new re-usable
-Django app. This one, in fact.</p>
-
-<p>DjanJinja exists to help you leverage the power of
-<a href="http://jinja.pocoo.org/2/">Jinja2</a> templates in your Django projects. It&#8217;s
-simple to get started.</p>
-
-<h2>Installing and Using DjanJinja</h2>
-
-<h3>Installing DjanJinja</h3>
-
-<ol>
-<li>Install DjanJinja using <code>easy_install djanjinja</code>, <code>pip install djanjinja</code>, or
-by grabbing a copy of the Mercurial repo and running <code>python setup.py
-install</code>.</li>
-<li>Add <code>'djanjinja'</code> to your <code>INSTALLED_APPS</code> list.</li>
-<li>(Optionally) add <code>'djanjinja.middleware.RequestContextMiddleware'</code> to your
-<code>MIDDLEWARE_CLASSES</code> list.</li>
-</ol>
-
-<p>It’s assumed that you have fairly recent versions of Jinja2 and Django
-installed. The author recommends the <em>most recent</em> stable versions of each,
-which should be installable via PyPI (i.e. a simple <code>easy_install</code> or <code>pip
-install</code>). A lot of people have their own ways of installing things, so the
-author hasn’t put any explicit requirements in the <code>setup.py</code> file. DjanJinja
-just expects to find <code>jinja2</code> and <code>django</code> on the import path.</p>
-
-<h3>Using DjanJinja</h3>
-
-<ul>
-<li>Instead of using <code>django.shortcuts.render_to_response</code>, use one of the
-Jinja2-based functions provided.</li>
-<li>Instead of using the Django loaders to load templates, get them from the
-Jinja2 environment created for you by DjanJinja.</li>
-<li>Instead of using Django’s provided generic views, use those contained within
-<code>djanjinja.generic</code> (at the moment the only one is <code>direct_to_template()</code>).</li>
-</ul>
-
-<h2>Shortcut Functions</h2>
-
-<p>DjanJinja provides you with two shortcut functions for rendering templates,
-<code>render_to_response</code> and <code>render_to_string</code>. These are very similar to those
-provided by Django in the <code>django.shortcuts</code> module, except they use Jinja2
-instead of the Django templating system. To use them from your views, just do
-<code>from djanjinja.views import render_to_response, render_to_string</code> at the top of
-your views module.</p>
-
-<h2>Bundles</h2>
-
-<p>A Jinja2 environment can contain additional filters, tests and global variables
-which will be available in all templates rendered through that environment.
-Since individual Django apps will have their own set of things to add to the
-environment, DjanJinja adds the concept of ‘bundles’; small objects containing
-some global variables, filters and tests. Each app may define any number of
-these bundles which can then be loaded as required.</p>
-
-<h3>Defining Bundles</h3>
-
-<p>It’s relatively easy to define a bundle; an example is shown below:</p>
-
-<pre><code>from djanjinja.loader import Bundle
-
-foo = Bundle()
-foo.globals['myvar'] = 12345
-
-@foo.envfilter
-def myenvfilter(environment, value):
-    pass # do something here...
-
-@foo.ctxfunction
-def mycontextfunction(context, value):
-    pass # do something here...
-</code></pre>
-
-<p>Here we define a bundle called <code>foo</code>, with a global variable of <code>myvar</code>
-containing the value <code>12345</code>, an environment filter and a context function (for
-more information on each of these please consult the Jinja2 documentation). The
-<code>Bundle</code> class also supplies these handy decorators (the full list can be found
-as <code>djanjinja.loader.Bundle.TYPES</code>) to define various components.</p>
-
-<p>DjanJinja expects to find bundles in a <code>bundles</code> submodule of your Django app.
-You can lay things out in one of two ways:</p>
-
-<ul>
-<li>Add a file called <code>bundles.py</code> to your app, and within this define multiple
-<code>Bundle</code> instances.</li>
-<li>Add a package called <code>bundles</code> to your app (i.e. a <code>bundles</code> directory
-containing an empty file called <code>__init__.py</code>), and within this define
-submodules for each of your bundles. Each submodule should have a top-level
-<code>bundle</code> variable which is an instance of the <code>Bundle</code> class.</li>
-</ul>
-
-<p>You can actually mix and match these; you could add some bundle instances to the
-<code>bundles/__init__.py</code> file with different names, in addition to having the
-submodules. These are loaded lazily, so DjanJinja sees no real difference. It
-doesn’t scour the <code>bundles</code> module for definitions, it just loads what you ask
-it to.</p>
-
-<h3>Addressing Bundles</h3>
-
-<p>In order to use the functions, filters and tests defined in a bundle, you first
-have to load it into the environment. Bundles are specified in two parts: the
-‘app label’ and the ‘bundle name’. The app label is simply the name of the app
-which contains it. For example, it may be <code>django.contrib.auth</code>, or simply
-<code>auth</code>, since you may just give the last part of the full name and DjanJinja
-will figure it out from looking at the <code>INSTALLED_APPS</code> setting.</p>
-
-<p>If a bundle is defined within a <code>bundles.py</code> or a <code>bundles/__init__.py</code> file,
-then the bundle name will be the name in the module with which it was defined.
-For example:</p>
-
-<pre><code># in the file `myapp/bundles.py`
-foo = Bundle()
-foo.globals['myvar'] = 12345
-</code></pre>
-
-<p>In this case, the app label will be <code>myapp</code>, and the bundle name will be <code>foo</code>.
-If the bundles are defined in submodules, then the bundle name will be the name
-of the submodule.</p>
-
-<h3>Loading Bundles</h3>
-
-<p>In order to load any bundles into the global Jinja2 environment, you need to specify a
-<code>DJANJINJA_BUNDLES</code> setting in your <code>settings.py</code> file. This is a list or tuple
-of bundle specifiers in an <code>'app_label.bundle_name'</code> format. For example:</p>
-
-<pre><code>DJANJINJA_BUNDLES = (
-    'djanjinja.cache',
-    'djanjinja.humanize',
-    'djanjinja.site',
-)
-</code></pre>
-
-<p>You can also add bundles to the environment programmatically. This is useful
-when:</p>
-
-<ul>
-<li>Your app needs to do some initial setup before a bundle is loaded.</li>
-<li>Your app relies on a particular bundle being present in the global environment
-anyway, and you don’t want the user to have to add the bundle to
-<code>DJANJINJA_BUNDLES</code> manually.</li>
-<li>Your app needs to load bundles dynamically.</li>
-<li>Your app wants to use a bundle locally, not globally.</li>
-</ul>
-
-<p>You can load a bundle into an environment like this:</p>
-
-<pre><code>import djanjinja
-env = djanjinja.get_env()
-env.load('app_label', 'bundle_name', reload=False)
-</code></pre>
-
-<p>This will load the bundle into the environment, passing through if it’s already
-loaded. If you specify <code>reload=True</code>, you can make it reload a bundle even if
-it’s been loaded.</p>
-
-<p>You should put this code somewhere where it will get executed when you want it
-to. If you want it to be executed immediately, as Django starts up, put it in
-<code>myapp/__init__.py</code>.</p>
-
-<p>You can also use a bundle within only one app, by using a local environment
-copied from the global environment. Here’s how you might do this:</p>
-
-<pre><code>import djanjinja
-global_env = djanjinja.get_env()
-local_env = global_env.copy()
-local_env.load('app_label', 'bundle_name')
-</code></pre>
-
-<p>You&#8217;d then use that local environment later on in your code. For example, the
-above code might be in <code>myapp/__init__.py</code>; so your views might look like this:</p>
-
-<pre><code>from django.http import HttpResponse
-from myapp import local_env
-
-def view(request):
-    template = local_env.get_template('template_name.html')
-    data = template.render({'key1': 'value1', 'key2': 'value2'})
-    return HttpResponse(content=data)
-</code></pre>
-
-<p>Of course, you’re probably going to want to use the usual shortcuts (i.e.
-<code>render_to_response()</code> and <code>render_to_string()</code>). You can build these easily
-using <code>djanjinja.views.shortcuts_for_environment()</code>:</p>
-
-<pre><code>from djanjinja.views import shortcuts_for_environment
-
-render_to_response, render_to_string = shortcuts_for_environment(local_env)
-</code></pre>
-
-<p>Do this at the top of your <code>views.py</code> file, and then you can use the generated
-functions throughout all of your views.</p>
-
-<h3>Caveats and Limitations</h3>
-
-<p>Jinja2 does not yet support scoped filters and tests; as a result of this, the
-contents of bundles specified in <code>DJANJINJA_BUNDLES</code> will be loaded into the global environment. It is important
-to make sure that definitions in your bundle do not override those in another
-bundle. This is especially important with threaded web applications, as multiple
-bundles overriding one another could cause unpredictable behavior in the
-templates.</p>
-
-<h3>Included Bundles</h3>
-
-<p>DjanJinja provides three bundles already which either replace Django
-counterparts or add some useful functionality to your Jinja2 templates:</p>
-
-<ul>
-<li><p><code>djanjinja.cache</code>: Loading this bundle will add a global <code>cache</code> object to the
-environment; this is the Django cache, and allows you to carry out caching
-operations from within your templates (such as <code>cache.get(key)</code>, et cetera).</p></li>
-<li><p><code>djanjinja.humanize</code>: This will add all of the filters contained within the
-<code>django.contrib.humanize</code> app; consult the official Django docs for more
-information on the filters provided.</p></li>
-<li><p><code>djanjinja.site</code>: This will add two functions to the global environment:
-<code>url</code>, and <code>setting</code>. The former acts like Django’s template tag, by reversing
-URLconf names and views into URLs, but because Jinja2 supports a richer
-syntax, it can be used via <code>{{ url(name, *args, **kwargs) }}</code> instead.
-<code>setting</code> attempts to resolve a setting name into a value, returning an
-optional default instead (i.e. <code>setting('MEDIA_URL', '/media')</code>).</p></li>
-</ul>
-
-<h2>Extensions</h2>
-
-<p>Jinja2 supports the concept of <em>environment extensions</em>; these are non-trivial
-plugins which enhance the Jinja2 templating engine itself. By default, the
-environment is configured with the <code>do</code> statement and the loop controls (i.e.
-<code>break</code> and <code>continue</code>), but if you want to add extensions to the environment
-then you can do so with the <code>JINJA_EXTENSIONS</code> setting. Just add this to your
-<code>settings.py</code> file:</p>
-
-<pre><code>JINJA_EXTENSIONS = (
-    'jinja2.ext.i18n', # i18n Extension
-    ...
-)
-</code></pre>
-
-<p>For all the extensions you wish to load. This will be passed in directly to the
-<code>jinja2.Environment</code> constructor.</p>
-
-<p>If you have set <code>USE_I18N = True</code> in your settings file, then DjanJinja will
-automatically initialize the i18n machinery for the Jinja2 environment, loading
-your Django translations during the bootstrapping process. For more information
-on how to use the Jinja2 i18n extension, please consult the Jinja2
-documentation.</p>
-
-<h3>Cache</h3>
-
-<p>DjanJinja also provides an extension for fragment caching using the Django cache
-system. The code for this borrows heavily from the example in the Jinja2
-documentation, but with a few extras thrown in. You can use the extension like
-this:</p>
-
-<pre><code>{% cache (parameter1, param2, param3), timeout %}
-    ...
-{% endcache %}
-</code></pre>
-
-<p>The tuple of parameters is used to generate the cache key for this fragment. You
-can place any object here, so long as it is suitable for serialization by the
-standard library <code>marshal</code> module. The cache key for the fragment is generated
-by marshaling the parameters, hashing them and then using the digest with a
-prefix as the key. This allows you to specify cached fragments which vary
-depending on multiple variables. The timeout is optional, and should be given in
-seconds.</p>
-
-<h2>404 and 500 Handlers</h2>
-
-<p>Your project’s URLconf must specify two variables—<code>handler404</code> and <code>handler500</code>—which give the name of a Django view to be processed in the event of a 404 &#8220;Not Found&#8221; and a 500 &#8220;Server Error&#8221; response respectively. These are set to a default which uses the Django templating system to render a response from templates called <code>404.html</code> and <code>500.html</code>. If you were to use the Jinja2 templating system instead, you will be able to define richer error pages, and your error pages will be able to inherit from and extend other Jinja2 master templates on the template path.</p>
-
-<p>It’s relatively simple to set Django up to do this. Simply override the handler variables like so from your <code>urls.py</code> file:</p>
-
-<pre><code>handler404 = 'djanjinja.handlers.page_not_found'
-handler500 = 'djanjinja.handlers.server_error'
-</code></pre>
-
-<h2><code>RequestContext</code></h2>
-
-<p>One of Django&#8217;s most useful features is the <code>RequestContext</code> class, which allows
-you to specify several context processors which each add some information to the
-context before templates are rendered. Luckily, this feature is
-template-agnostic, and is therefore fully compatible with DjanJinja.</p>
-
-<p>However, DjanJinja also provides you with some very helpful shortcuts for using
-request contexts. Usually, without DjanJinja, you would use them like this:</p>
-
-<pre><code>from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-def myview(request):
-    context = {'foo': bar, 'spam': eggs}
-    return render_to_response('template_name.html',
-        context, context_instance=RequestContext())
-</code></pre>
-
-<p>To be honest,this doesn&#8217;t look very much like a &#8216;shortcut&#8217; at all. For this
-reason, DjanJinja contains a subclass of <code>RequestContext</code> specialised for
-Jinja2, which is used like this:</p>
-
-<pre><code>from djanjinja.views import RequestContext
-
-def myview(request):
-    context = RequestContext(request, {'foo': bar, 'spam': eggs})
-    return context.render_response('template_name.html')
-</code></pre>
-
-<p>This code is much more concise, but loses none of the flexibility of the
-previous example. The main changes made are the addition of <code>render_response</code>
-and <code>render_string</code> methods to the context object itself. This is highly
-specialised to rendering Jinja2 templates, so it may not be a very reusable
-approach (indeed, other code which does not use Jinja2 will need to use the full
-Django syntax), but it works for the problem domain it was designed for.</p>
-
-<h2>Middleware</h2>
-
-<p>One important thing to note from before is that each time a <code>RequestContext</code>
-instance is constructed, it is necessary to explicitly pass the request. In
-object-oriented programming, and Python expecially, when we have functions to
-which we must always pass an object of a certain type, it makes sense to make
-that function a <em>method</em> of the type. When that function is not, in fact, a
-function, but a constructor, this seems more difficult. However, thanks to a
-feature of Python known as metaprogramming, we can do this very easily. Because
-it&#8217;s not exactly obvious how to do so, DjanJinja includes a special piece of
-middleware which can help make your code a lot shorter yet <em>still</em> retain all
-the functionality and flexibility of the previous two examples.</p>
-
-<p>To use this middleware, simply add
-<code>'djanjinja.middleware.RequestContextMiddleware'</code> to your <code>MIDDLEWARE_CLASSES</code>
-list in the settings module of your project. Then, you can write view code like
-this:</p>
-
-<pre><code>def myview(request):
-    return request.Context({'foo': bar, 'spam': eggs}).render_response(
-        'template_name.html')
-</code></pre>
-
-<p>As you can see, we&#8217;ve greatly reduced the verbosity of the previous code, but
-it&#8217;s still obvious what this code does. The middleware attaches a <code>Context</code>
-attribute to each request object. This attribute is in fact a fully-fledged
-Python class, which may itself be subclassed and modified later on. When
-constructed, it behaves almost exactly the same as the usual <code>RequestContext</code>,
-only it uses the request object to which it has been attached, so you don&#8217;t have
-to pass it in to the constructor every time.</p>
-
-<h2>Template Loading</h2>
-
-<p>DjanJinja hooks directly into the Django template loader machinery to load
-templates. This means you can mix Jinja2 templates freely with Django templates,
-in your <code>TEMPLATE_DIRS</code> and your applications, and render each type
-independently and seamlessly. If you want more information on how it actually
-works, please consult the <code>djanjinja/environment.py</code> file.</p>
-
-<h2>License</h2>
-
-<p>This software is licensed under the following MIT-style license:</p>
-
-<blockquote>
-  <p>Copyright (c) 2009 Zachary Voase</p>
-  
-  <p>Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the &#8220;Software&#8221;), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:</p>
-  
-  <p>The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.</p>
-  
-  <p>THE SOFTWARE IS PROVIDED &#8220;AS IS&#8221;, WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.</p>
-</blockquote>
-
-<h2>Author</h2>
-
-<p>Zachary Voase can be found on <a href="http://twitter.com/zacharyvoase">Twitter</a>.</p>

README.mdown

-# DjanJinja v0.6
-
-DjanJinja: the sound you make when you've got peanut butter stuck to the roof of
-your mouth. Incidentally, it also happens to be the name of a new re-usable
-Django app. This one, in fact.
-
-DjanJinja exists to help you leverage the power of
-[Jinja2](http://jinja.pocoo.org/2/) templates in your Django projects. It's
-simple to get started.
-
-## Installing and Using DjanJinja
-
-### Installing DjanJinja
-
-1. Install DjanJinja using `easy_install djanjinja`, `pip install djanjinja`, or
-   by grabbing a copy of the Mercurial repo and running `python setup.py
-   install`.
-2. Add `'djanjinja'` to your `INSTALLED_APPS` list.
-3. (Optionally) add `'djanjinja.middleware.RequestContextMiddleware'` to your
-   `MIDDLEWARE_CLASSES` list.
-
-It’s assumed that you have fairly recent versions of Jinja2 and Django
-installed. The author recommends the *most recent* stable versions of each,
-which should be installable via PyPI (i.e. a simple `easy_install` or `pip
-install`). A lot of people have their own ways of installing things, so the
-author hasn’t put any explicit requirements in the `setup.py` file. DjanJinja
-just expects to find `jinja2` and `django` on the import path.
-
-### Using DjanJinja
-
-* Instead of using `django.shortcuts.render_to_response`, use one of the
-  Jinja2-based functions provided.
-* Instead of using the Django loaders to load templates, get them from the
-  Jinja2 environment created for you by DjanJinja.
-* Instead of using Django’s provided generic views, use those contained within
-  `djanjinja.generic` (at the moment the only one is `direct_to_template()`).
-
-## Shortcut Functions
-
-DjanJinja provides you with two shortcut functions for rendering templates,
-`render_to_response` and `render_to_string`. These are very similar to those
-provided by Django in the `django.shortcuts` module, except they use Jinja2
-instead of the Django templating system. To use them from your views, just do
-`from djanjinja.views import render_to_response, render_to_string` at the top of
-your views module.
-
-## Bundles
-
-A Jinja2 environment can contain additional filters, tests and global variables
-which will be available in all templates rendered through that environment.
-Since individual Django apps will have their own set of things to add to the
-environment, DjanJinja adds the concept of ‘bundles’; small objects containing
-some global variables, filters and tests. Each app may define any number of
-these bundles which can then be loaded as required.
-
-### Defining Bundles
-
-It’s relatively easy to define a bundle; an example is shown below:
-    
-    from djanjinja.loader import Bundle
-    
-    foo = Bundle()
-    foo.globals['myvar'] = 12345
-    
-    @foo.envfilter
-    def myenvfilter(environment, value):
-        pass # do something here...
-    
-    @foo.ctxfunction
-    def mycontextfunction(context, value):
-        pass # do something here...
-
-Here we define a bundle called `foo`, with a global variable of `myvar`
-containing the value `12345`, an environment filter and a context function (for
-more information on each of these please consult the Jinja2 documentation). The
-`Bundle` class also supplies these handy decorators (the full list can be found
-as `djanjinja.loader.Bundle.TYPES`) to define various components.
-
-DjanJinja expects to find bundles in a `bundles` submodule of your Django app.
-You can lay things out in one of two ways:
-
-* Add a file called `bundles.py` to your app, and within this define multiple
-  `Bundle` instances.
-* Add a package called `bundles` to your app (i.e. a `bundles` directory
-  containing an empty file called `__init__.py`), and within this define
-  submodules for each of your bundles. Each submodule should have a top-level
-  `bundle` variable which is an instance of the `Bundle` class.
-
-You can actually mix and match these; you could add some bundle instances to the
-`bundles/__init__.py` file with different names, in addition to having the
-submodules. These are loaded lazily, so DjanJinja sees no real difference. It
-doesn’t scour the `bundles` module for definitions, it just loads what you ask
-it to.
-
-### Addressing Bundles
-
-In order to use the functions, filters and tests defined in a bundle, you first
-have to load it into the environment. Bundles are specified in two parts: the
-‘app label’ and the ‘bundle name’. The app label is simply the name of the app
-which contains it. For example, it may be `django.contrib.auth`, or simply
-`auth`, since you may just give the last part of the full name and DjanJinja
-will figure it out from looking at the `INSTALLED_APPS` setting.
-
-If a bundle is defined within a `bundles.py` or a `bundles/__init__.py` file,
-then the bundle name will be the name in the module with which it was defined.
-For example:
-    
-    # in the file `myapp/bundles.py`
-    foo = Bundle()
-    foo.globals['myvar'] = 12345
-
-In this case, the app label will be `myapp`, and the bundle name will be `foo`.
-If the bundles are defined in submodules, then the bundle name will be the name
-of the submodule.
-
-### Loading Bundles
-
-In order to load any bundles into the global Jinja2 environment, you need to specify a
-`DJANJINJA_BUNDLES` setting in your `settings.py` file. This is a list or tuple
-of bundle specifiers in an `'app_label.bundle_name'` format. For example:
-
-    DJANJINJA_BUNDLES = (
-        'djanjinja.cache',
-        'djanjinja.humanize',
-        'djanjinja.site',
-    )
-
-You can also add bundles to the environment programmatically. This is useful
-when:
-
-* Your app needs to do some initial setup before a bundle is loaded.
-* Your app relies on a particular bundle being present in the global environment
-  anyway, and you don’t want the user to have to add the bundle to
-  `DJANJINJA_BUNDLES` manually.
-* Your app needs to load bundles dynamically.
-* Your app wants to use a bundle locally, not globally.
-
-You can load a bundle into an environment like this:
-
-    import djanjinja
-    env = djanjinja.get_env()
-    env.load('app_label', 'bundle_name', reload=False)
-
-This will load the bundle into the environment, passing through if it’s already
-loaded. If you specify `reload=True`, you can make it reload a bundle even if
-it’s been loaded.
-
-You should put this code somewhere where it will get executed when you want it
-to. If you want it to be executed immediately, as Django starts up, put it in
-`myapp/__init__.py`.
-
-You can also use a bundle within only one app, by using a local environment
-copied from the global environment. Here’s how you might do this:
-
-    import djanjinja
-    global_env = djanjinja.get_env()
-    local_env = global_env.copy()
-    local_env.load('app_label', 'bundle_name')
-
-You'd then use that local environment later on in your code. For example, the
-above code might be in `myapp/__init__.py`; so your views might look like this:
-
-    from django.http import HttpResponse
-    from myapp import local_env
-    
-    def view(request):
-        template = local_env.get_template('template_name.html')
-        data = template.render({'key1': 'value1', 'key2': 'value2'})
-        return HttpResponse(content=data)
-
-Of course, you’re probably going to want to use the usual shortcuts (i.e.
-`render_to_response()` and `render_to_string()`). You can build these easily
-using `djanjinja.views.shortcuts_for_environment()`:
-
-    from djanjinja.views import shortcuts_for_environment
-    
-    render_to_response, render_to_string = shortcuts_for_environment(local_env)
-
-Do this at the top of your `views.py` file, and then you can use the generated
-functions throughout all of your views.
-
-### Caveats and Limitations
-
-Jinja2 does not yet support scoped filters and tests; as a result of this, the
-contents of bundles specified in `DJANJINJA_BUNDLES` will be loaded into the global environment. It is important
-to make sure that definitions in your bundle do not override those in another
-bundle. This is especially important with threaded web applications, as multiple
-bundles overriding one another could cause unpredictable behavior in the
-templates.
-
-### Included Bundles
-
-DjanJinja provides three bundles already which either replace Django
-counterparts or add some useful functionality to your Jinja2 templates:
-    
-* `djanjinja.cache`: Loading this bundle will add a global `cache` object to the
-  environment; this is the Django cache, and allows you to carry out caching
-  operations from within your templates (such as `cache.get(key)`, et cetera).
-
-* `djanjinja.humanize`: This will add all of the filters contained within the
-  `django.contrib.humanize` app; consult the official Django docs for more
-  information on the filters provided.
-
-* `djanjinja.site`: This will add two functions to the global environment:
-  `url`, and `setting`. The former acts like Django’s template tag, by reversing
-  URLconf names and views into URLs, but because Jinja2 supports a richer
-  syntax, it can be used via `{{ url(name, *args, **kwargs) }}` instead.
-  `setting` attempts to resolve a setting name into a value, returning an
-  optional default instead (i.e. `setting('MEDIA_URL', '/media')`).
-
-## Extensions
-
-Jinja2 supports the concept of *environment extensions*; these are non-trivial
-plugins which enhance the Jinja2 templating engine itself. By default, the
-environment is configured with the `do` statement and the loop controls (i.e.
-`break` and `continue`), but if you want to add extensions to the environment
-then you can do so with the `JINJA_EXTENSIONS` setting. Just add this to your
-`settings.py` file:
-    
-    JINJA_EXTENSIONS = (
-        'jinja2.ext.i18n', # i18n Extension
-        ...
-    )
-
-For all the extensions you wish to load. This will be passed in directly to the
-`jinja2.Environment` constructor.
-
-If you have set `USE_I18N = True` in your settings file, then DjanJinja will
-automatically initialize the i18n machinery for the Jinja2 environment, loading
-your Django translations during the bootstrapping process. For more information
-on how to use the Jinja2 i18n extension, please consult the Jinja2
-documentation.
-
-### Cache
-
-DjanJinja also provides an extension for fragment caching using the Django cache
-system. The code for this borrows heavily from the example in the Jinja2
-documentation, but with a few extras thrown in. You can use the extension like
-this:
-    
-    {% cache (parameter1, param2, param3), timeout %}
-        ...
-    {% endcache %}
-
-The tuple of parameters is used to generate the cache key for this fragment. You
-can place any object here, so long as it is suitable for serialization by the
-standard library `marshal` module. The cache key for the fragment is generated
-by marshaling the parameters, hashing them and then using the digest with a
-prefix as the key. This allows you to specify cached fragments which vary
-depending on multiple variables. The timeout is optional, and should be given in
-seconds.
-
-## 404 and 500 Handlers
-
-Your project’s URLconf must specify two variables—`handler404` and `handler500`—which give the name of a Django view to be processed in the event of a 404 "Not Found" and a 500 "Server Error" response respectively. These are set to a default which uses the Django templating system to render a response from templates called `404.html` and `500.html`. If you were to use the Jinja2 templating system instead, you will be able to define richer error pages, and your error pages will be able to inherit from and extend other Jinja2 master templates on the template path.
-
-It’s relatively simple to set Django up to do this. Simply override the handler variables like so from your `urls.py` file:
-
-    handler404 = 'djanjinja.handlers.page_not_found'
-    handler500 = 'djanjinja.handlers.server_error'
-
-## `RequestContext`
-
-One of Django's most useful features is the `RequestContext` class, which allows
-you to specify several context processors which each add some information to the
-context before templates are rendered. Luckily, this feature is
-template-agnostic, and is therefore fully compatible with DjanJinja.
-
-However, DjanJinja also provides you with some very helpful shortcuts for using
-request contexts. Usually, without DjanJinja, you would use them like this:
-    
-    from django.shortcuts import render_to_response
-    from django.template import RequestContext
-    
-    def myview(request):
-        context = {'foo': bar, 'spam': eggs}
-        return render_to_response('template_name.html',
-            context, context_instance=RequestContext())
-
-To be honest,this doesn't look very much like a 'shortcut' at all. For this
-reason, DjanJinja contains a subclass of `RequestContext` specialised for
-Jinja2, which is used like this:
-
-    from djanjinja.views import RequestContext
-    
-    def myview(request):
-        context = RequestContext(request, {'foo': bar, 'spam': eggs})
-        return context.render_response('template_name.html')
-
-This code is much more concise, but loses none of the flexibility of the
-previous example. The main changes made are the addition of `render_response`
-and `render_string` methods to the context object itself. This is highly
-specialised to rendering Jinja2 templates, so it may not be a very reusable
-approach (indeed, other code which does not use Jinja2 will need to use the full
-Django syntax), but it works for the problem domain it was designed for.
-
-## Middleware
-
-One important thing to note from before is that each time a `RequestContext`
-instance is constructed, it is necessary to explicitly pass the request. In
-object-oriented programming, and Python expecially, when we have functions to
-which we must always pass an object of a certain type, it makes sense to make
-that function a *method* of the type. When that function is not, in fact, a
-function, but a constructor, this seems more difficult. However, thanks to a
-feature of Python known as metaprogramming, we can do this very easily. Because
-it's not exactly obvious how to do so, DjanJinja includes a special piece of
-middleware which can help make your code a lot shorter yet *still* retain all
-the functionality and flexibility of the previous two examples.
-
-To use this middleware, simply add
-`'djanjinja.middleware.RequestContextMiddleware'` to your `MIDDLEWARE_CLASSES`
-list in the settings module of your project. Then, you can write view code like
-this:
-
-    def myview(request):
-        return request.Context({'foo': bar, 'spam': eggs}).render_response(
-            'template_name.html')
-
-As you can see, we've greatly reduced the verbosity of the previous code, but
-it's still obvious what this code does. The middleware attaches a `Context`
-attribute to each request object. This attribute is in fact a fully-fledged
-Python class, which may itself be subclassed and modified later on. When
-constructed, it behaves almost exactly the same as the usual `RequestContext`,
-only it uses the request object to which it has been attached, so you don't have
-to pass it in to the constructor every time.
-
-## Template Loading
-
-DjanJinja hooks directly into the Django template loader machinery to load
-templates. This means you can mix Jinja2 templates freely with Django templates,
-in your `TEMPLATE_DIRS` and your applications, and render each type
-independently and seamlessly. If you want more information on how it actually
-works, please consult the `djanjinja/environment.py` file.
-
-## License
-
-This software is licensed under the following MIT-style license:
-    
-> Copyright (c) 2009 Zachary Voase
-> 
-> Permission is hereby granted, free of charge, to any person
-> obtaining a copy of this software and associated documentation
-> files (the "Software"), to deal in the Software without
-> restriction, including without limitation the rights to use,
-> copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the
-> Software is furnished to do so, subject to the following
-> conditions:
-> 
-> The above copyright notice and this permission notice shall be
-> included in all copies or substantial portions of the Software.
-> 
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-> OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-> HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-> OTHER DEALINGS IN THE SOFTWARE.
-
-## Author
-
-Zachary Voase can be found on [Twitter](http://twitter.com/zacharyvoase).