This looks reasonable.  I think it would also be reasonable to just make
this the standard 'view' functionality, since afaict the current
functionality is a subset of this.


On Sun, Sep 13, 2009 at 12:57 PM, Chris McDonough <> wrote:

> Here's some sci fi I wrote up about a "page" ZCML directive.  As Tim
> Hoffman
> suggested, maybe the fact that the "page" is passed into the template would
> give us enough "pull" capability to avoid any of the other hacks I proposed
> to
> push global names into every rendered template.
> Note that the "view" directive could probably eventually be changed to do
> everything that the "page" directive I describe below does.
> Comments appreciated.
> ======================
> ```` is a package which adds a ``page`` ZCML directive
> to the set of directives that may be used under BFG.  You might use a
> ``page`` directive in places where you would otherwise use the
> built-in repoze.bfg ``view`` directive.  Defining a ``page`` directive
> effectively creates a single BFG view "under the hood", and owns
> attributes similar to those of a view directive.  However, the
> ``page`` directive differs from the BFG ``view`` directive in a number
> of important ways:
> - The ``page`` directive allows you to associate a *template* with the
>   page being defined.  The machinery behind the ``page`` directive is
>   capable of rendering an associated template, unlike a view, which
>   must find and render a template itself.
> - A ``page`` directive, like a BFG ``view`` directive, points at a
>   callable which accepts two arguments: ``context`` and ``request``.
>   This callable must return a Response object *or* a Python
>   dictionary.  This is unlike a BFG ``view`` callable, which always
>   returns a Response object (and must never return a dictionary).
>   The ``callable`` which a ``page`` directive points at may optionally
>   be a class.  If the page directive's ``callable`` attribute points
>   at a class, that class must have an ``__init__`` method that accepts
>   two arguments: ``context`` and ``request``.  That class must further
>   define a ``__call__`` method which accepts no arguments and which
>   returns a dictionary or a Response object.
>   If the page callable returns a Python dictionary, the ``template``
>   named within the directive will be passed the dictionary as its
>   keyword arguments, and the ``page`` implementation will return the
>   resulting rendered template in a response to the user.  The callable
>   object (whatever object was used to define the page ``callable``)
>   will be automatically inserted into the set of keyword arguments
>   passed to the template as ``page``.  If the callable object was a
>   class, an instance of that class will be inserted into the keyword
>   arguments as ``page``.
>   If the ``callable`` associated with a ``page`` directive returns a
>   Response object (an object with the attributes ``status``,
>   ``headerlist`` and ``app_iter``), any template associated with the
>   ``page`` declaration is ignored, and the response is passed back to
>   BFG.  For example, if your page callable returns an ``HTTPFound``
>   response, no template rendering will be performed::
>     from webob.exc import HTTPFound
>     return HTTPFound(location='') # templating avoided
> Here's an example of a page directive which acts as a default view::
>   <page
>    template="templates/"
>    callable=".pages.my_page"
>    />
> The ``template`` attribute is optional.  If one is not named, and the
> callable returns a dictionary, an error will be thrown at rendering
> time.
> Special ZCML Attributes
> -----------------------
> The directive accepts attributes other than ``template`` and ``callable``.
> attr
>   ```` defaults to using the ``__call__`` method of the
>   page callable to obtain a response dictionary.  The ``attr`` value
>   allows you to vary that method name.  For example, if your class had
>   a method named ``index`` and you wanted to use this method instead
>   of ``__call__``, you'd say ``attr="index"`` in the page ZCML
>   definition.  This is most useful when the page definition is a
>   class.
> for
>   A Python dotted-path name representing the Python class that the
>   :term:`context` must be an instance of, *or* the :term:`interface`
>   that the :term:`context` must provide in order for this view to be
>   found and called.
> name
>   The *view name*.  Read and understand :ref:`traversal_chapter` to
>   understand the concept of a view name.
> permission
>   The name of a *permission* that the user must possess in order to
>   call the view.  See :ref:`view_security_section` for more
>   information about view security and permissions.
> request_method
>   This value can either be one of the strings 'GET', 'POST', 'PUT',
>   'DELETE', or 'HEAD' representing an HTTP ``REQUEST_METHOD``.  A view
>   declaration with this attribute ensures that the view will only be
>   called when the request's ``method`` (aka ``REQUEST_METHOD``) string
>   matches the supplied value.
> request_param
>   This value can be any string.  A view declaration with this
>   attribute ensures that the view will only be called when the request
>   has a key in the ``request.params`` dictionary (an HTTP ``GET`` or
>   ``POST`` variable) that has a name which matches the supplied value.
>   If the value supplied to the attribute has a ``=`` sign in it,
>   e.g. ``request_params="foo=123"``, then the key (``foo``) must both
>   exist in the ``request.params`` dictionary, and the value must match
>   the right hand side of the expression (``123``) for the view to
>   "match" the current request.
> containment
>   This value should be a Python dotted-path string representing the
>   class that a graph traversal parent object of the :term:`context`
>   must be an instance of (or :term:`interface` that a parent object
>   must provide) in order for this view to be found and called.  Your
>   models must be "location-aware" to use this feature.  See
>   :ref:`location_aware` for more information about location-awareness.
> route_name
>   *This attribute services an advanced feature that isn't often used
>   unless you want to perform traversal *after* a route has matched.*
>   This value must match the ``name`` of a ``<route>`` declaration (see
>   :ref:`urldispatch_chapter`) that must match before this view will be
>   called.  The ``<route>`` declaration specified by ``route_name`` must
>   exist in ZCML before the view that names the route
>   (XML-ordering-wise) .  Note that the ``<route>`` declaration
>   referred to by ``route_name`` usually has a ``*traverse`` token in
>   the value of its ``path`` attribute, representing a part of the path
>   that will be used by traversal against the result of the route's
>   :term:`root factory`.  See :ref:`hybrid_chapter` for more
>   information on using this advanced feature.
> request_type
>   This value should be a Python dotted-path string representing the
>   :term:`interface` that the :term:`request` must have in order for
>   this view to be found and called.  See
>   :ref:`view_request_types_section` for more information about request
>   types.  For backwards compatibility with :mod:`repoze.bfg` version
>   1.0, this value may also be an HTTP ``REQUEST_METHOD`` string, e.g.
>   ('GET', 'HEAD', 'PUT', 'POST', or 'DELETE').  Passing request method
>   strings as a ``request_type`` is deprecated.  Use the
>   ``request_method`` attribute instead for maximum forward
>   compatibility.
> Special Keyword Names When A Callable Returns A Dictionary
> ----------------------------------------------------------
> Several keyword names in a dictionary return value of a page callable
> are treated specially by the page implementation.  These values are
> passed through to the template during rendering, but they also
> influence the response returned to the user separate from any template
> rendering.  Page callables should set these values into the dictionary
> they return to influence response attributes.
> content_type
>   Defines the content-type of the resulting response,
>   e.g. ``text/xml``.
> 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')]``.
> status
>   A WSGI-style status code (e.g. ``200 OK``) describing the status of
>   the response.
> charset
>   The character set (e.g. ``UTF-8``) of the 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 headerlist, this is
>   purely a convenience.
> Default Template Filename Extension Mappings
> --------------------------------------------
> A file extension mapping is used to determine which templating system
> renderer to use to render any given template.  By default, a single
> filename-extension-to-renderer mapping is used: any template name with
> a filename extension of ".pt" is assumed to be rendered via a
> Chameleon ZPT template.
> By default, if a template renderer cannot be recognized by its
> extension, it will be assumed that a Chameleon text renderer should be
> used to render the template.
> Adding and Overriding Template Filename Extension Mappings
> ----------------------------------------------------------
> Additonal declarations can be made which override a default
> file-extension-to-renderer mapping or add a new
> file-extension-to-renderer mapping.  This is accomplished via one or
> more separate ZCML directives.
> For example, to add Jinja2 rendering (after installing the
> repoze.bfg.jinja2" package), whereby filenames that end in ``.jinja``
> are rendered by the Jinja2 renderer::
>   <utility provides=""
>            name=".jinja"
>            component="repoze.bfg.jinja2.render_template_to_response"/>
> 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::
>   <utility provides=""
>            name=".pt"
>            component="my.package.pt_renderer"/>
> By default, when a template extension is unrecognized, the Chameleon
> text templating engine is assumed.  You can override the default
> renderer by creating an ``IPageRenderer`` utility which has no
> ``name``::
>   <utility provides=""
>            component="my.package.default_renderer"/>
> The ``component`` named within any of these directives must be a
> callable which accepts the following arguments: ``(template_name,
> request, **kw)``.  It must return a Response object.
> _______________________________________________
> Repoze-dev mailing list
Repoze-dev mailing list

Reply via email to