Commits

Anonymous committed 2a5b5a4

Added information on environment overlaying/copying.

  • Participants
  • Parent commits 1e9dda3

Comments (0)

Files changed (4)

 * 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
 
 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
 
 ### Loading Bundles
 
-In order to load any bundles into the Jinja2 environment, you need to specify a
+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:
 
 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 environment
+* 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:
 
 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 will be loaded into the global environment. It is important
+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
 depending on multiple variables. The timeout is optional, and should be given in
 seconds.
 
-## Shortcut Functions
+## 404 and 500 Handlers
 
-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.
+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`
 

djanjinja/environment.py

         return loader.load(
             app_label, bundle_name, environment=self, reload=reload)
     
+    def copy(self):
+        """Create a copy of the environment."""
+        
+        copy = self.overlay()
+        for attr in ['loaded_bundles', 'globals', 'filters', 'tests']:
+            setattr(copy, attr, getattr(self, attr).copy())
+        
+        return copy
+    
     # pylint: disable-msg=C0111
     def adder(attribute, wrapper, name, docstring):
         

djanjinja/loader.py

     bundle = get_bundle(app_label, bundle_name)
     if (bundle not in environment.loaded_bundles) or reload:
         bundle.merge_into(environment)
+        environment.loaded_bundles.add(bundle)
     return bundle

djanjinja/views.py

 template-rendering shortcuts, and features an extended ``RequestContext``.
 """
 
+from functools import partial
+
 from django import template
 from django.conf import settings
 from django.http import HttpResponse
 
 from djanjinja import get_env
 
+
 DEFAULT_CONTENT_TYPE = getattr(settings, 'DEFAULT_CONTENT_TYPE', 'text/html')
 
 
     @classmethod
     def with_request(cls, request):
         """Return a `RequestContext` subclass for a specified request."""
+        
         # Subclasses `RequestContext` with a value for `request`, so that it
         # does not need it as an explicit request argument for initialization.
         return type(
     
     def render_string(self, filename):
         """Render a given template name to a string, using this context."""
+        
         return render_to_string(filename, context=self)
     
     def render_response(self, filename, mimetype=DEFAULT_CONTENT_TYPE):
         """Render a given template name to a response, using this context."""
+        
         return render_to_response(filename, context=self, mimetype=mimetype)
 
 
 def context_to_dict(context):
     """Flattens a Django context into a single dictionary."""
+    
     if not isinstance(context, template.Context):
         return context
     
     dict_out = {}
+    
     # This helps us handle the order of dictionaries in the context. By
     # default, the most recent (and therefore most significant/important)
     # sub-dictionaries are at the front of the list. This means that variables
     return dict_out
 
 
-def render_to_string(filename, context=None):
+def render_to_string(filename, context=None, environment=None):
     """Renders a given template name to a string."""
+    
     if context is None:
         context = {}
     
-    return get_env().get_template(filename).render(
+    if environment is None:
+        environment = get_env()
+    
+    return environment.get_template(filename).render(
         context_to_dict(context))
 
 
-def render_to_response(filename, context=None, mimetype=DEFAULT_CONTENT_TYPE):
+def render_to_response(filename, context=None, mimetype=DEFAULT_CONTENT_TYPE,
+        environment=None):
     """Renders a given template name to a ``django.http.HttpResponse``."""
+    
     return HttpResponse(
-        render_to_string(filename, context=context), mimetype=mimetype)
+        render_to_string(filename, context=context), mimetype=mimetype,
+        environment=environment)
+
+
+def shortcuts_for_environment(environment):
+    """Returns shortcuts pre-configured for a given environment."""
+    
+    return (
+        partial(render_to_string, environment=environment),
+        partial(render_to_response, environment=environment))