summaryrefslogtreecommitdiff
path: root/docs/narr/renderers.rst
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-12-19 18:04:55 -0500
committerChris McDonough <chrism@plope.com>2010-12-19 18:04:55 -0500
commita59c789b2bb4a1de5f79537cc2f1022c97bb51f6 (patch)
treeb5052ade4fc0718c9d2ff05b4a51e6f59f85f912 /docs/narr/renderers.rst
parente8f14759a3cf00b78735ef7e7ae8949f68b29b2b (diff)
downloadpyramid-a59c789b2bb4a1de5f79537cc2f1022c97bb51f6.tar.gz
pyramid-a59c789b2bb4a1de5f79537cc2f1022c97bb51f6.tar.bz2
pyramid-a59c789b2bb4a1de5f79537cc2f1022c97bb51f6.zip
- Split off "Renderers" as its own chapter from "Views" chapter in narrative
documentation.
Diffstat (limited to 'docs/narr/renderers.rst')
-rw-r--r--docs/narr/renderers.rst594
1 files changed, 594 insertions, 0 deletions
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
new file mode 100644
index 000000000..3804fcf42
--- /dev/null
+++ b/docs/narr/renderers.rst
@@ -0,0 +1,594 @@
+.. _renderers_chapter:
+
+Renderers
+=========
+
+In the :ref:`views_chapter` chapter, we said that a view callable must
+return a :term:`Response` object. We lied. A :term:`renderer` is a service
+that attempts to convert a non-Response return value of a function, class, or
+instance that acts as a :term:`view callable` to a :term:`Response` object.
+
+Overview
+--------
+
+A view needn't *always* return a Response object. If a view happens to
+return something which does not implement the Pyramid Response interface,
+:app:`Pyramid` will attempt to use a :term:`renderer` to construct a
+response. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ def hello_world(request):
+ return {'content':'Hello!'}
+
+The above example returns a *dictionary* from the view callable. A
+dictionary does not implement the Pyramid response interface, so you might
+believe that this example would fail. However, since a ``renderer`` is
+associated with the view callable through its :term:`view configuration` (in
+this case, using a ``renderer`` argument passed to
+:func:`pyramid.view.view_config`), if the view does *not* return a Response
+object, the renderer will attempt to convert the result of the view to a
+response on the developer's behalf.
+
+Of course, if no renderer is associated with a view's configuration,
+returning anything except an object which implements the Response interface
+will result in an error. And, if a renderer *is* used, whatever is returned
+by the view must be compatible with the particular kind of renderer used, or
+an error may occur during view invocation.
+
+One exception exists: it is *always* OK to return a Response object, even
+when a ``renderer`` is configured. If a view callable returns a response
+object from a view that is configured with a renderer, the renderer is
+bypassed entirely.
+
+Various types of renderers exist, including serialization renderers
+and renderers which use templating systems. See also
+:ref:`views_which_use_a_renderer`.
+
+
+.. index::
+ single: renderer
+ single: view renderer
+
+.. _views_which_use_a_renderer:
+
+Writing View Callables Which Use a Renderer
+-------------------------------------------
+
+As we've seen, view callables needn't always return a Response object.
+Instead, they may return an arbitrary Python object, with the expectation
+that a :term:`renderer` will convert that object into a response instance on
+your behalf. Some renderers use a templating system; other renderers use
+object serialization techniques.
+
+View configuration can vary the renderer associated with a view callable via
+the ``renderer`` attribute. For example, this call to
+:meth:`pyramid.config.Configurator.add_view` associates the ``json`` renderer
+with a view callable:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_view('myproject.views.my_view', renderer='json')
+
+When this configuration is added to an application, the
+``myproject.views.my_view`` view callable will now use a ``json`` renderer,
+which renders view return values to a :term:`JSON` response serialization.
+
+Other built-in renderers include renderers which use the :term:`Chameleon`
+templating language to render a dictionary to a response.
+
+If the :term:`view callable` associated with a :term:`view configuration`
+returns a Response object directly (an object with the attributes ``status``,
+``headerlist`` and ``app_iter``), any renderer associated with the view
+configuration is ignored, and the response is passed back to :app:`Pyramid`
+unmolested. For example, if your view callable returns an instance of the
+:class:`pyramid.httpexceptions.HTTPFound` class as a response, no renderer
+will be employed.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.httpexceptions import HTTPFound
+
+ def view(request):
+ return HTTPFound(location='http://example.com') # any renderer avoided
+
+Views which use a renderer can vary non-body response attributes (such as
+headers and the HTTP status code) by attaching properties to the request.
+See :ref:`response_request_attrs`.
+
+Additional renderers can be added by developers to the system as necessary
+(see :ref:`adding_and_overriding_renderers`).
+
+.. index::
+ single: renderers (built-in)
+ single: built-in renderers
+
+.. _built_in_renderers:
+
+Built-In Renderers
+------------------
+
+Several built-in renderers exist in :app:`Pyramid`. These renderers can be
+used in the ``renderer`` attribute of view configurations.
+
+.. index::
+ pair: renderer; string
+
+``string``: String Renderer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``string`` renderer is a renderer which renders a view callable result to
+a string. If a view callable returns a non-Response object, and the
+``string`` renderer is associated in that view's configuration, the result
+will be to run the object through the Python ``str`` function to generate a
+string. Note that if a Unicode object is returned by the view callable, it
+is not ``str()`` -ified.
+
+Here's an example of a view that returns a dictionary. If the ``string``
+renderer is specified in the configuration for this view, the view will
+render the returned dictionary to the ``str()`` representation of the
+dictionary:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config(renderer='string')
+ def hello_world(request):
+ return {'content':'Hello!'}
+
+The body of the response returned by such a view will be a string
+representing the ``str()`` serialization of the return value:
+
+.. code-block:: python
+ :linenos:
+
+ {'content': 'Hello!'}
+
+Views which use the string renderer can vary non-body response attributes by
+attaching properties to the request. See :ref:`response_request_attrs`.
+
+.. index::
+ pair: renderer; JSON
+
+``json``: JSON Renderer
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``json`` renderer renders view callable results to :term:`JSON`. It
+passes the return value through the ``json.dumps`` standard library function,
+and wraps the result in a response object. It also sets the response
+content-type to ``application/json``.
+
+Here's an example of a view that returns a dictionary. Since the ``json``
+renderer is specified in the configuration for this view, the view will
+render the returned dictionary to a JSON serialization:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config(renderer='json')
+ def hello_world(request):
+ return {'content':'Hello!'}
+
+The body of the response returned by such a view will be a string
+representing the JSON serialization of the return value:
+
+.. code-block:: python
+ :linenos:
+
+ '{"content": "Hello!"}'
+
+The return value needn't be a dictionary, but the return value must contain
+values serializable by :func:`json.dumps`.
+
+You can configure a view to use the JSON renderer by naming ``json`` as the
+``renderer`` argument of a view configuration, e.g. by using
+:meth:`pyramid.config.Configurator.add_view`:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='json')
+
+
+Views which use the JSON renderer can vary non-body response attributes by
+attaching properties to the request. See :ref:`response_request_attrs`.
+
+.. index::
+ pair: renderer; chameleon
+
+.. _chameleon_template_renderers:
+
+``*.pt`` or ``*.txt``: Chameleon Template Renderers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Two built-in renderers exist for :term:`Chameleon` templates.
+
+If the ``renderer`` attribute of a view configuration is an absolute path, a
+relative path or :term:`asset specification` which has a final path element
+with a filename extension of ``.pt``, the Chameleon ZPT renderer is used.
+See :ref:`chameleon_zpt_templates` for more information about ZPT templates.
+
+If the ``renderer`` attribute of a view configuration is an absolute path or
+a :term:`asset specification` which has a final path element with a filename
+extension of ``.txt``, the :term:`Chameleon` text renderer is used. See
+:ref:`chameleon_zpt_templates` for more information about Chameleon text
+templates.
+
+The behavior of these renderers is the same, except for the engine
+used to render the template.
+
+When a ``renderer`` attribute that names a template path or :term:`asset
+specification` (e.g. ``myproject:templates/foo.pt`` or
+``myproject:templates/foo.txt``) is used, the view must return a
+:term:`Response` object or a Python *dictionary*. If the view callable with
+an associated template returns a Python dictionary, the named template will
+be passed the dictionary as its keyword arguments, and the template renderer
+implementation will return the resulting rendered template in a response to
+the user. If the view callable returns anything but a Response object or a
+dictionary, an error will be raised.
+
+Before passing keywords to the template, the keyword arguments derived from
+the dictionary returned by the view are augmented. The callable object --
+whatever object was used to define the ``view`` -- will be automatically
+inserted into the set of keyword arguments passed to the template as the
+``view`` keyword. If the view callable was a class, the ``view`` keyword
+will be an instance of that class. Also inserted into the keywords passed to
+the template are ``renderer_name`` (the string used in the ``renderer``
+attribute of the directive), ``renderer_info`` (an object containing
+renderer-related information), ``context`` (the context resource of the view
+used to render the template), and ``request`` (the request passed to the view
+used to render the template).
+
+Here's an example view configuration which uses a Chameleon ZPT renderer:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='myproject:templates/foo.pt')
+
+Here's an example view configuration which uses a Chameleon text renderer:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='myproject:templates/foo.txt')
+
+Views which use a Chameleon renderer can vary response attributes by
+attaching properties to the request. See :ref:`response_request_attrs`.
+
+.. index::
+ pair: renderer; mako
+
+.. _mako_template_renderers:
+
+``*.mak`` or ``*.mako``: Mako Template Renderer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``Mako`` template renderer renders views using a Mako template. When
+used, the view must return a Response object or a Python *dictionary*. The
+dictionary items will then be used in the global template space. If the view
+callable returns anything but a Response object, or a dictionary, an error
+will be raised.
+
+When using a ``renderer`` argument to a :term:`view configuration` to specify
+a Mako template, the value of the ``renderer`` may be a path relative to the
+``mako.directories`` setting (e.g. ``some/template.mak``) or, alternately,
+it may be a :term:`asset specification`
+(e.g. ``apackage:templates/sometemplate.mak``). Mako templates may
+internally inherit other Mako templates using a relative filename or a
+:term:`asset specification` as desired.
+
+Here's an example view configuration which uses a relative path:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='foo.mak')
+
+It's important to note that in Mako's case, the 'relative' path name
+``foo.mak`` above is not relative to the package, but is relative to the
+directory (or directories) configured for Mako via the ``mako.directories``
+configuration file setting.
+
+The renderer can also be provided in :term:`asset specification`
+format. Here's an example view configuration which uses one:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='mypackage:templates/foo.mak')
+
+The above configuration will use the file named ``foo.mak`` in the
+``templates`` directory of the ``mypackage`` package.
+
+The ``Mako`` template renderer can take additional arguments beyond the
+standard ``reload_templates`` setting, see the :ref:`environment_chapter` for
+additional :ref:`mako_template_renderer_settings`.
+
+.. index::
+ single: response headers (from a renderer)
+ single: renderer response headers
+
+.. _response_request_attrs:
+
+Varying Attributes of Rendered Responses
+----------------------------------------
+
+Before a response constructed by a :term:`renderer` is returned to
+:app:`Pyramid`, several attributes of the request are examined which have the
+potential to influence response behavior.
+
+View callables that don't directly return a response should set these
+attributes on the ``request`` object via ``setattr`` during their execution,
+to influence associated response attributes.
+
+``response_content_type``
+ Defines the content-type of the resulting response,
+ e.g. ``text/xml``.
+
+``response_headerlist``
+ A sequence of tuples describing cookie values that should be set in the
+ response, e.g. ``[('Set-Cookie', 'abc=123'), ('X-My-Header', 'foo')]``.
+
+``response_status``
+ A WSGI-style status code (e.g. ``200 OK``) describing the status of the
+ response.
+
+``response_charset``
+ The character set (e.g. ``UTF-8``) of the response.
+
+``response_cache_for``
+ A value in seconds which will influence ``Cache-Control`` and ``Expires``
+ headers in the returned response. The same can also be achieved by
+ returning various values in the ``response_headerlist``, this is purely a
+ convenience.
+
+For example, if you need to change the response status from within a view
+callable that uses a renderer, assign the ``response_status`` attribute to
+the request before returning a result:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(name='gone', renderer='templates/gone.pt')
+ def myview(request):
+ request.response_status = '404 Not Found'
+ return {'URL':request.URL}
+
+For more information on attributes of the request, see the API
+documentation in :ref:`request_module`.
+
+.. index::
+ single: renderer (adding)
+
+.. _adding_and_overriding_renderers:
+
+Adding and Overriding Renderers
+-------------------------------
+
+New templating systems and serializers can be associated with :app:`Pyramid`
+renderer names. To this end, configuration declarations can be made which
+override an existing :term:`renderer factory`, and which add a new renderer
+factory.
+
+Renderers can be registered imperatively using the
+:meth:`pyramid.config.Configurator.add_renderer` API.
+
+.. note:: The tasks described in this section can also be performed via
+ :term:`declarative configuration`. See
+ :ref:`zcml_adding_and_overriding_renderers`.
+
+For example, to add a renderer which renders views which have a
+``renderer`` attribute that is a path that ends in ``.jinja2``:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')
+
+The first argument is the renderer name. The second argument is a reference
+to an implementation of a :term:`renderer factory` or a :term:`dotted Python
+name` referring to such an object.
+
+.. _adding_a_renderer:
+
+Adding a New Renderer
+~~~~~~~~~~~~~~~~~~~~~
+
+You may add a new renderer by creating and registering a :term:`renderer
+factory`.
+
+A renderer factory implementation is typically a class with the
+following interface:
+
+.. code-block:: python
+ :linenos:
+
+ class RendererFactory:
+ def __init__(self, info):
+ """ Constructor: ``info`` will be an object having the
+ the following attributes: ``name`` (the renderer name), ``package``
+ (the package that was 'current' at the time the renderer was
+ registered), ``type`` (the renderer type name), ``registry``
+ (the current application registry) and ``settings`` (the
+ deployment settings dictionary).
+ """
+
+ def __call__(self, value, system):
+ """ Call a the renderer implementation with the value and
+ the system value passed in as arguments and return the
+ result (a string or unicode object). The value is the
+ return value of a view. The system value is a dictionary
+ containing available system values (e.g. ``view``,
+ ``context``, and ``request``). """
+
+The formal interface definition of the ``info`` object passed to a renderer
+factory constructor is available as :class:`pyramid.interfaces.IRendererInfo`.
+
+There are essentially two different kinds of renderer factories:
+
+- A renderer factory which expects to accept a :term:`asset
+ specification`, or an absolute path, as the ``name`` attribute of the
+ ``info`` object fed to its constructor. These renderer factories are
+ registered with a ``name`` value that begins with a dot (``.``). These
+ types of renderer factories usually relate to a file on the filesystem,
+ such as a template.
+
+- A renderer factory which expects to accept a token that does not represent
+ a filesystem path or a asset specification in the ``name``
+ attribute of the ``info`` object fed to its constructor. These renderer
+ factories are registered with a ``name`` value that does not begin with a
+ dot. These renderer factories are typically object serializers.
+
+.. sidebar:: Asset Specifications
+
+ A asset specification is a colon-delimited identifier for a
+ :term:`asset`. The colon separates a Python :term:`package`
+ name from a package subpath. For example, the asset
+ specification ``my.package:static/baz.css`` identifies the file named
+ ``baz.css`` in the ``static`` subdirectory of the ``my.package`` Python
+ :term:`package`.
+
+Here's an example of the registration of a simple renderer factory via
+:meth:`pyramid.config.Configurator.add_renderer`:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')
+
+Adding the above code to your application startup configuration will
+allow you to use the ``my.package.MyAMFRenderer`` renderer factory
+implementation in view configurations. Your application can use this
+renderer by specifying ``amf`` in the ``renderer`` attribute of a
+:term:`view configuration`:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(renderer='amf')
+ def myview(request):
+ return {'Hello':'world'}
+
+At startup time, when a :term:`view configuration` is encountered, which
+has a ``name`` attribute that does not contain a dot, the full ``name``
+value is used to construct a renderer from the associated renderer
+factory. In this case, the view configuration will create an instance
+of an ``AMFRenderer`` for each view configuration which includes ``amf``
+as its renderer value. The ``name`` passed to the ``AMFRenderer``
+constructor will always be ``amf``.
+
+Here's an example of the registration of a more complicated renderer
+factory, which expects to be passed a filesystem path:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_renderer(name='.jinja2',
+ factory='my.package.MyJinja2Renderer')
+
+Adding the above code to your application startup will allow you to use the
+``my.package.MyJinja2Renderer`` renderer factory implementation in view
+configurations by referring to any ``renderer`` which *ends in* ``.jinja`` in
+the ``renderer`` attribute of a :term:`view configuration`:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(renderer='templates/mytemplate.jinja2')
+ def myview(request):
+ return {'Hello':'world'}
+
+When a :term:`view configuration` is encountered at startup time, which
+has a ``name`` attribute that does contain a dot, the value of the name
+attribute is split on its final dot. The second element of the split is
+typically the filename extension. This extension is used to look up a
+renderer factory for the configured view. Then the value of
+``renderer`` is passed to the factory to create a renderer for the view.
+In this case, the view configuration will create an instance of a
+``Jinja2Renderer`` for each view configuration which includes anything
+ending with ``.jinja2`` in its ``renderer`` value. The ``name`` passed
+to the ``Jinja2Renderer`` constructor will be the full value that was
+set as ``renderer=`` in the view configuration.
+
+See also :ref:`renderer_directive` and
+:meth:`pyramid.config.Configurator.add_renderer`.
+
+Overriding an Existing Renderer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can associate more than one filename extension with the same existing
+renderer implementation as necessary if you need to use a different file
+extension for the same kinds of templates. For example, to associate the
+``.zpt`` extension with the Chameleon ZPT renderer factory, use the
+:meth:`pyramid.config.Configurator.add_renderer` method:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_renderer('.zpt', 'pyramid.chameleon_zpt.renderer_factory')
+
+After you do this, :app:`Pyramid` will treat templates ending in both the
+``.pt`` and ``.zpt`` filename extensions as Chameleon ZPT templates.
+
+To override the default mapping in which files with a ``.pt`` extension are
+rendered via a Chameleon ZPT page template renderer, use a variation on the
+following in your application's startup code:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_renderer('.pt', 'mypackage.pt_renderer')
+
+After you do this, the :term:`renderer factory` in
+``mypackage.pt_renderer`` will be used to render templates which end
+in ``.pt``, replacing the default Chameleon ZPT renderer.
+
+To associate a *default* renderer with *all* view configurations (even
+ones which do not possess a ``renderer`` attribute), pass ``None`` as
+the ``name`` attribute to the renderer tag:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_renderer(None, 'mypackage.json_renderer_factory')
+